Truyền thông giữa các quy trình - Đường ống được đặt tên
Các đường ống được dùng để liên lạc giữa các quá trình liên quan. Chúng ta có thể sử dụng các đường ống để giao tiếp quy trình không liên quan, chẳng hạn, chúng ta muốn thực thi chương trình khách từ một thiết bị đầu cuối và chương trình máy chủ từ thiết bị đầu cuối khác? Câu trả lời là Không. Sau đó, làm thế nào chúng ta có thể đạt được giao tiếp các quy trình không liên quan, câu trả lời đơn giản là Ống có tên. Mặc dù điều này hoạt động cho các quá trình liên quan, nó không có ý nghĩa gì khi sử dụng các đường ống được đặt tên để giao tiếp quá trình liên quan.
Chúng tôi đã sử dụng một đường ống để giao tiếp một chiều và hai đường ống để giao tiếp hai chiều. Điều kiện tương tự có áp dụng cho Ống được đặt tên không. Câu trả lời là không, chúng ta có thể sử dụng một đường ống được đặt tên có thể được sử dụng cho giao tiếp hai chiều (giao tiếp giữa máy chủ và máy khách, cộng với máy khách và máy chủ cùng một lúc) vì Named Pipe hỗ trợ giao tiếp hai chiều.
Một tên khác cho đường ống được đặt tên là FIFO (First-In-First-Out). Chúng ta hãy xem lệnh gọi hệ thống (mknod ()) để tạo một đường ống có tên, đây là một loại tệp đặc biệt.
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int mknod(const char *pathname, mode_t mode, dev_t dev);
Lệnh gọi hệ thống này sẽ tạo một tệp đặc biệt hoặc nút hệ thống tệp, chẳng hạn như tệp thông thường, tệp thiết bị hoặc FIFO. Các đối số cho lệnh gọi hệ thống là tên đường dẫn, chế độ và nhà phát triển. Tên đường dẫn cùng với các thuộc tính của chế độ và thông tin thiết bị. Tên đường dẫn là tương đối, nếu thư mục không được chỉ định, nó sẽ được tạo trong thư mục hiện tại. Chế độ được chỉ định là chế độ của tệp chỉ định loại tệp như loại tệp và chế độ tệp như được đề cập trong bảng sau. Trường dev là để chỉ định thông tin thiết bị như số thiết bị chính và phụ.
Loại tệp | Sự miêu tả | Loại tệp | Sự miêu tả |
---|---|---|---|
S_IFBLK | khối đặc biệt | S_IFREG | Tệp thông thường |
S_IFCHR | nhân vật đặc biệt | S_IFDIR | Danh mục |
S_IFIFO | FIFO đặc biệt | S_IFLNK | Liên kết tượng trưng |
Chế độ tệp | Sự miêu tả | Chế độ tệp | Sự miêu tả |
---|---|---|---|
S_IRWXU | Đọc, viết, thực thi / tìm kiếm bởi chủ sở hữu | S_IWGRP | Quyền viết, nhóm |
S_IRUSR | Quyền đọc, chủ sở hữu | S_IXGRP | Thực thi / quyền tìm kiếm, nhóm |
S_IWUSR | Quyền viết, chủ sở hữu | S_IRWXO | Đọc, viết, thực thi / tìm kiếm bởi những người khác |
S_IXUSR | Thực thi / quyền tìm kiếm, chủ sở hữu | S_IROTH | Quyền đọc, những người khác |
S_IRWXG | Đọc, ghi, thực thi / tìm kiếm theo nhóm | S_IWOTH | Quyền viết, những người khác |
S_IRGRP | Quyền đọc, nhóm | S_IXOTH | Thực thi / quyền tìm kiếm, các quyền khác |
Chế độ tệp cũng có thể được biểu thị bằng ký hiệu bát phân chẳng hạn như 0XYZ, trong đó X đại diện cho chủ sở hữu, Y đại diện cho nhóm và Z đại diện cho những người khác. Giá trị của X, Y hoặc Z có thể nằm trong khoảng từ 0 đến 7. Giá trị đọc, ghi và thực thi lần lượt là 4, 2, 1. Nếu cần kết hợp đọc, ghi và thực thi, sau đó thêm các giá trị tương ứng.
Giả sử, nếu chúng ta đề cập, 0640, thì điều này có nghĩa là đọc và ghi (4 + 2 = 6) cho chủ sở hữu, đọc (4) cho nhóm và không có quyền (0) cho người khác.
Lệnh gọi này sẽ trả về 0 khi thành công và -1 trong trường hợp thất bại. Để biết nguyên nhân của lỗi, hãy kiểm tra với biến errno hoặc hàm perror ().
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode)
Hàm thư viện này tạo một tệp đặc biệt FIFO, tệp này được sử dụng cho đường ống được đặt tên. Các đối số của hàm này là tên tệp và chế độ. Tên tệp có thể là đường dẫn tuyệt đối hoặc đường dẫn tương đối. Nếu tên đường dẫn đầy đủ (hoặc đường dẫn tuyệt đối) không được cung cấp, tệp sẽ được tạo trong thư mục hiện tại của quá trình thực thi. Thông tin về chế độ tệp được mô tả trong lệnh gọi hệ thống mknod ().
Lệnh gọi này sẽ trả về 0 khi thành công và -1 trong trường hợp thất bại. Để biết nguyên nhân của lỗi, hãy kiểm tra với biến errno hoặc hàm perror ().
Chúng ta hãy xem xét một chương trình chạy máy chủ trên một thiết bị đầu cuối và chạy máy khách trên thiết bị đầu cuối khác. Chương trình sẽ chỉ thực hiện giao tiếp một chiều. Máy khách chấp nhận đầu vào của người dùng và gửi thông báo đến máy chủ, máy chủ in thông báo trên đầu ra. Quá trình được tiếp tục cho đến khi người dùng nhập chuỗi “kết thúc”.
Hãy để chúng tôi hiểu điều này với một ví dụ -
Step 1 - Tạo hai tiến trình, một là máy chủ mười lăm và một quy trình khác là máy chủ toàn phần.
Step 2 - Quá trình máy chủ thực hiện như sau:
Tạo một đường ống được đặt tên (sử dụng lệnh gọi hệ thống mknod ()) với tên “MYFIFO”, nếu chưa được tạo.
Mở đường ống được đặt tên cho mục đích chỉ đọc.
Tại đây, đã tạo FIFO với quyền đọc và ghi cho Chủ sở hữu. Đọc cho Nhóm và không có quyền cho Người khác.
Chờ đợi vô hạn tin nhắn từ Khách hàng.
Nếu thông báo nhận được từ máy khách không phải là "kết thúc", hãy in thông báo. Nếu thông báo là "kết thúc", đóng năm mươi và kết thúc quá trình.
Step 3 - Quy trình khách hàng thực hiện như sau:
Mở đường ống được đặt tên chỉ cho mục đích ghi.
Chấp nhận chuỗi từ người dùng.
Kiểm tra, nếu người dùng nhập “kết thúc” hoặc khác với “kết thúc”. Dù bằng cách nào, nó sẽ gửi một thông báo đến máy chủ. Tuy nhiên, nếu chuỗi là "kết thúc", điều này sẽ đóng FIFO và cũng kết thúc quá trình.
Lặp lại vô hạn cho đến khi người dùng nhập chuỗi “end”.
Bây giờ chúng ta hãy xem xét tệp máy chủ FIFO.
/* Filename: fifoserver.c */
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#define FIFO_FILE "MYFIFO"
int main() {
int fd;
char readbuf[80];
char end[10];
int to_end;
int read_bytes;
/* Create the FIFO if it does not exist */
mknod(FIFO_FILE, S_IFIFO|0640, 0);
strcpy(end, "end");
while(1) {
fd = open(FIFO_FILE, O_RDONLY);
read_bytes = read(fd, readbuf, sizeof(readbuf));
readbuf[read_bytes] = '\0';
printf("Received string: \"%s\" and length is %d\n", readbuf, (int)strlen(readbuf));
to_end = strcmp(readbuf, end);
if (to_end == 0) {
close(fd);
break;
}
}
return 0;
}
Các bước biên dịch và thực hiện
Received string: "this is string 1" and length is 16
Received string: "fifo test" and length is 9
Received string: "fifo client and server" and length is 22
Received string: "end" and length is 3
Bây giờ, chúng ta hãy xem mã mẫu khách hàng FIFO.
/* Filename: fifoclient.c */
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#define FIFO_FILE "MYFIFO"
int main() {
int fd;
int end_process;
int stringlen;
char readbuf[80];
char end_str[5];
printf("FIFO_CLIENT: Send messages, infinitely, to end enter \"end\"\n");
fd = open(FIFO_FILE, O_CREAT|O_WRONLY);
strcpy(end_str, "end");
while (1) {
printf("Enter string: ");
fgets(readbuf, sizeof(readbuf), stdin);
stringlen = strlen(readbuf);
readbuf[stringlen - 1] = '\0';
end_process = strcmp(readbuf, end_str);
//printf("end_process is %d\n", end_process);
if (end_process != 0) {
write(fd, readbuf, strlen(readbuf));
printf("Sent string: \"%s\" and string length is %d\n", readbuf, (int)strlen(readbuf));
} else {
write(fd, readbuf, strlen(readbuf));
printf("Sent string: \"%s\" and string length is %d\n", readbuf, (int)strlen(readbuf));
close(fd);
break;
}
}
return 0;
}
Hãy xem xét kết quả đầu ra.
Các bước biên dịch và thực hiện
FIFO_CLIENT: Send messages, infinitely, to end enter "end"
Enter string: this is string 1
Sent string: "this is string 1" and string length is 16
Enter string: fifo test
Sent string: "fifo test" and string length is 9
Enter string: fifo client and server
Sent string: "fifo client and server" and string length is 22
Enter string: end
Sent string: "end" and string length is 3
Giao tiếp hai chiều sử dụng ống được đặt tên
Thông tin liên lạc giữa các đường ống có nghĩa là một chiều. Các đường ống bị hạn chế đối với giao tiếp một chiều nói chung và cần ít nhất hai ống để giao tiếp hai chiều. Các đường ống chỉ dành cho các quá trình liên quan đến nhau. Pipes không thể được sử dụng cho giao tiếp các quá trình không liên quan, chẳng hạn, nếu chúng ta muốn thực hiện một quá trình từ một thiết bị đầu cuối và một quá trình khác từ một thiết bị đầu cuối khác, thì không thể thực hiện được với đường ống. Chúng ta có bất kỳ cách đơn giản nào để giao tiếp giữa hai quy trình, nói những quy trình không liên quan một cách đơn giản? Câu trả lời là CÓ. Đường ống được đặt tên có nghĩa là để giao tiếp giữa hai hoặc nhiều quy trình không liên quan và cũng có thể có giao tiếp hai chiều.
Hiện tại, chúng ta đã thấy giao tiếp một chiều giữa các đường ống được đặt tên, tức là, các thông báo từ máy khách đến máy chủ. Bây giờ, chúng ta hãy xem xét giao tiếp hai chiều, tức là máy khách gửi thông điệp đến máy chủ và máy chủ nhận thông báo và gửi lại một thông báo khác cho máy khách bằng cách sử dụng cùng một đường dẫn được đặt tên.
Sau đây là một ví dụ -
Step 1 - Tạo hai tiến trình, một là Fifoserver_twoway và một quá trình khác là Fifoclient_twoway.
Step 2 - Quá trình máy chủ thực hiện như sau:
Tạo một đường ống được đặt tên (sử dụng hàm thư viện mkfifo ()) với tên “Fifo_twoway” trong thư mục / tmp, nếu chưa được tạo.
Mở đường ống được đặt tên cho mục đích đọc và ghi.
Tại đây, đã tạo FIFO với quyền đọc và ghi cho Chủ sở hữu. Đọc cho Nhóm và không có quyền cho Người khác.
Chờ đợi vô hạn cho một tin nhắn từ khách hàng.
Nếu thông báo nhận được từ máy khách không phải là "kết thúc", hãy in thông báo và đảo ngược chuỗi. Chuỗi đảo ngược được gửi trở lại máy khách. Nếu thông báo là "kết thúc", đóng năm mươi và kết thúc quá trình.
Step 3 - Quy trình khách hàng thực hiện như sau:
Mở đường ống được đặt tên cho mục đích đọc và ghi.
Chấp nhận chuỗi từ người dùng.
Kiểm tra, nếu người dùng nhập “kết thúc” hoặc khác với “kết thúc”. Dù bằng cách nào, nó sẽ gửi một thông báo đến máy chủ. Tuy nhiên, nếu chuỗi là "kết thúc", điều này sẽ đóng FIFO và cũng kết thúc quá trình.
Nếu thông báo được gửi không phải là “kết thúc”, nó sẽ đợi thông báo (chuỗi đảo ngược) từ máy khách và in chuỗi đã đảo ngược.
Lặp lại vô hạn cho đến khi người dùng nhập chuỗi “end”.
Bây giờ, chúng ta hãy xem mã mẫu máy chủ FIFO.
/* Filename: fifoserver_twoway.c */
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#define FIFO_FILE "/tmp/fifo_twoway"
void reverse_string(char *);
int main() {
int fd;
char readbuf[80];
char end[10];
int to_end;
int read_bytes;
/* Create the FIFO if it does not exist */
mkfifo(FIFO_FILE, S_IFIFO|0640);
strcpy(end, "end");
fd = open(FIFO_FILE, O_RDWR);
while(1) {
read_bytes = read(fd, readbuf, sizeof(readbuf));
readbuf[read_bytes] = '\0';
printf("FIFOSERVER: Received string: \"%s\" and length is %d\n", readbuf, (int)strlen(readbuf));
to_end = strcmp(readbuf, end);
if (to_end == 0) {
close(fd);
break;
}
reverse_string(readbuf);
printf("FIFOSERVER: Sending Reversed String: \"%s\" and length is %d\n", readbuf, (int) strlen(readbuf));
write(fd, readbuf, strlen(readbuf));
/*
sleep - This is to make sure other process reads this, otherwise this
process would retrieve the message
*/
sleep(2);
}
return 0;
}
void reverse_string(char *str) {
int last, limit, first;
char temp;
last = strlen(str) - 1;
limit = last/2;
first = 0;
while (first < last) {
temp = str[first];
str[first] = str[last];
str[last] = temp;
first++;
last--;
}
return;
}
Các bước biên dịch và thực hiện
FIFOSERVER: Received string: "LINUX IPCs" and length is 10
FIFOSERVER: Sending Reversed String: "sCPI XUNIL" and length is 10
FIFOSERVER: Received string: "Inter Process Communication" and length is 27
FIFOSERVER: Sending Reversed String: "noitacinummoC ssecorP retnI" and length is 27
FIFOSERVER: Received string: "end" and length is 3
Bây giờ, chúng ta hãy xem mã mẫu khách hàng FIFO.
/* Filename: fifoclient_twoway.c */
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#define FIFO_FILE "/tmp/fifo_twoway"
int main() {
int fd;
int end_process;
int stringlen;
int read_bytes;
char readbuf[80];
char end_str[5];
printf("FIFO_CLIENT: Send messages, infinitely, to end enter \"end\"\n");
fd = open(FIFO_FILE, O_CREAT|O_RDWR);
strcpy(end_str, "end");
while (1) {
printf("Enter string: ");
fgets(readbuf, sizeof(readbuf), stdin);
stringlen = strlen(readbuf);
readbuf[stringlen - 1] = '\0';
end_process = strcmp(readbuf, end_str);
//printf("end_process is %d\n", end_process);
if (end_process != 0) {
write(fd, readbuf, strlen(readbuf));
printf("FIFOCLIENT: Sent string: \"%s\" and string length is %d\n", readbuf, (int)strlen(readbuf));
read_bytes = read(fd, readbuf, sizeof(readbuf));
readbuf[read_bytes] = '\0';
printf("FIFOCLIENT: Received string: \"%s\" and length is %d\n", readbuf, (int)strlen(readbuf));
} else {
write(fd, readbuf, strlen(readbuf));
printf("FIFOCLIENT: Sent string: \"%s\" and string length is %d\n", readbuf, (int)strlen(readbuf));
close(fd);
break;
}
}
return 0;
}
Các bước biên dịch và thực hiện
FIFO_CLIENT: Send messages, infinitely, to end enter "end"
Enter string: LINUX IPCs
FIFOCLIENT: Sent string: "LINUX IPCs" and string length is 10
FIFOCLIENT: Received string: "sCPI XUNIL" and length is 10
Enter string: Inter Process Communication
FIFOCLIENT: Sent string: "Inter Process Communication" and string length is 27
FIFOCLIENT: Received string: "noitacinummoC ssecorP retnI" and length is 27
Enter string: end
FIFOCLIENT: Sent string: "end" and string length is 3