linux程序设计---进程间通信:管道 参考资料:linux程序设计 作者:马修 1,popen调用。 在一个进程中启动另一个程序作为一个新的进程运行,并且这两个进程之间可以进行通信。使用到得函数是: FILE *popen(cosnt char *command,const char *open_mode); int pclose(FILE *stream_to_close); popen函数运行一个进程启动另一个进程,并能对它发送数据和接受数据。command字符串是待运行程序的名字和相应的参数。open_mode必须是“r”或者“w”. 如果open_mode是“r”,调用者程序可以使用被调用程序的输出。调用者程序利用popen返回的那个*FILE类型的指针使用一般的stdio库函数就可以读取这个流文件。 如果open_mode是“w”,调用者程序可以使用fwrite调用向被调用者发送数据。而被调用者程序可以在自己的标准输入上读到这些数据。 pclose函数关闭与之关联的文件流,pclose只有在popen进程结束之后才能返回。返回的被关闭进程的退出码。 #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <string.h> int main() { FILE *read_fp; char buffer[BUFSIZ + 1]; int chars_read; memset(buffer, '\0', sizeof(buffer)); read_fp = popen("ps -ax", "r"); if (read_fp != NULL) { chars_read = fread(buffer, sizeof(char), BUFSIZ, read_fp); while (chars_read > 0) { buffer[chars_read - 1] = '\0'; printf("Reading:-\n %s\n", buffer); chars_read = fread(buffer, sizeof(char), BUFSIZ, read_fp); } pclose(read_fp); exit(EXIT_SUCCESS); } exit(EXIT_FAILURE); } 2,pipe函数 #include <unistd.h> int pipe(int file_description[2]); //操作成功返回0,失败返回-1. file_description[2]有两个文件描述符组成的数值,从file_description[0]读管道数据,向file_description[1]中写数据。 #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <string.h> int main() { int data_processed; int file_pipes[2]; const char some_data[] = "123"; char buffer[BUFSIZ + 1]; pid_t fork_result; memset(buffer, '\0', sizeof(buffer)); if (pipe(file_pipes) == 0) { fork_result = fork(); if (fork_result == -1) { fprintf(stderr, "Fork failure"); exit(EXIT_FAILURE); } // We've made sure the fork worked, so if fork_result equals zero, we're in the child process. if (fork_result == 0) { data_processed = read(file_pipes[0], buffer, BUFSIZ); printf("Read %d bytes: %s\n", data_processed, buffer); exit(EXIT_SUCCESS); } // Otherwise, we must be the parent process. else { data_processed = write(file_pipes[1], some_data, strlen(some_data)); printf("Wrote %d bytes\n", data_processed); } } exit(EXIT_SUCCESS); } 3,dup函数 #include<unistd.h> int dup(int file_description);//打开一个新的文件描述符。 int dup2(int file_descritpion_one,int file_description_2); #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <string.h> int main() { int data_processed; int file_pipes[2]; const char some_data[] = "123"; pid_t fork_result; if (pipe(file_pipes) == 0) { fork_result = fork(); if (fork_result == (pid_t)-1) { fprintf(stderr, "Fork failure"); exit(EXIT_FAILURE); } if (fork_result == (pid_t)0) { close(0); dup(file_pipes[0]); close(file_pipes[0]); close(file_pipes[1]); execlp("od", "od", "-c", (char *)0); exit(EXIT_FAILURE); } else { close(file_pipes[0]); data_processed = write(file_pipes[1], some_data, strlen(some_data)); close(file_pipes[1]); printf("%d - wrote %d bytes\n", (int)getpid(), data_processed); } } exit(EXIT_SUCCESS); } 4,命名管道fifo文件 现在为止,程序之间的通信还是在相关程序之间进行,这些程序都是有一个共同的祖先启动的。 如何在两个互不相干的两个程序之间进行通信?需要使用命名管道。 命令行创建命名管道的方式: mknod filename p //此方法在有些系统上不识别。 mkfifo filename //此方法是创建命名管道的通用方法。 程序中创建命名管道函数: #include <sys/types.h> #include <sys/stat.h> int mkfifo(const char *filename,mode_t mode); //创建命名管道的通用方法。 int mknod(const char *filename,mode_t mode | S_IFIFO,(dev_t)0);//不常用方法。 open(const char *path,O_RDONLY); open调用将阻塞,除非有其他进程以写方式打开同一个FIFO文件。 open(const char *path,O_RDONLY | O_NONBLOCK); 即使没有进程以写方式打开这个FIFO文件,这个open调用也成功并立刻返回。 open(const char *path,O_WRONLY); open调用将阻塞,知道其他进程以读方式打开同一个FIFO文件。 open(const char *path,O_WRONLY | O_NONBLOCK); 立刻返回,但是如果没有其他进程以读方式打开这个FIFO文件,open调用将返回一个错误“-1”,而FIFO文件也不会真的被打开。 如果真的有其他进程以读的方式打开这个FIFO文件,我们就可以通过open返回的文件描述符对这个FIFO文件进行写操作。 服务器程序:server.c #include "client.h" #include <ctype.h> int main() { int server_fifo_fd, client_fifo_fd; struct data_to_pass_st my_data; int read_res; char client_fifo[256]; char *tmp_char_ptr; mkfifo(SERVER_FIFO_NAME, 0777); server_fifo_fd = open(SERVER_FIFO_NAME, O_RDONLY); if (server_fifo_fd == -1) { fprintf(stderr, "Server fifo failure\n"); exit(EXIT_FAILURE); } sleep(10); /* lets clients queue for demo purposes */ do { read_res = read(server_fifo_fd, &my_data, sizeof(my_data)); if (read_res > 0) { // In this next stage, we perform some processing on the data just read from the client. // We convert all the characters in some_data to uppercase and combine the CLIENT_FIFO_NAME // with the received client_pid. tmp_char_ptr = my_data.some_data; while (*tmp_char_ptr) { *tmp_char_ptr = toupper(*tmp_char_ptr); tmp_char_ptr++; } sprintf(client_fifo, CLIENT_FIFO_NAME, my_data.client_pid); // Then we send the processed data back, opening the client pipe in write-only, blocking mode. // Finally, we shut down the server FIFO by closing the file and then unlinking the FIFO. client_fifo_fd = open(client_fifo, O_WRONLY); if (client_fifo_fd != -1) { write(client_fifo_fd, &my_data, sizeof(my_data)); close(client_fifo_fd); } } } while (read_res > 0); close(server_fifo_fd); unlink(SERVER_FIFO_NAME); exit(EXIT_SUCCESS); } 客户端程序:client.c // Here's the client, client.c. The first part of this program opens the server FIFO, // if it already exists, as a file. It then gets its own process ID, which forms some // of the data that will be sent to the server. The client FIFO is created, ready for // the next section. #include "client.h" #include <ctype.h> int main() { int server_fifo_fd, client_fifo_fd; struct data_to_pass_st my_data; int times_to_send; char client_fifo[256]; server_fifo_fd = open(SERVER_FIFO_NAME, O_WRONLY); if (server_fifo_fd == -1) { fprintf(stderr, "Sorry, no server\n"); exit(EXIT_FAILURE); } my_data.client_pid = getpid(); sprintf(client_fifo, CLIENT_FIFO_NAME, my_data.client_pid); if (mkfifo(client_fifo, 0777) == -1) { fprintf(stderr, "Sorry, can't make %s\n", client_fifo); exit(EXIT_FAILURE); } // For each of the five loops, the client data is sent to the server. // Then the client FIFO is opened (read-only, blocking mode) and the data read back. // Finally, the server FIFO is closed and the client FIFO removed from memory. for (times_to_send = 0; times_to_send < 5; times_to_send++) { sprintf(my_data.some_data, "Hello from %d", my_data.client_pid); printf("%d sent %s, ", my_data.client_pid, my_data.some_data); write(server_fifo_fd, &my_data, sizeof(my_data)); client_fifo_fd = open(client_fifo, O_RDONLY); if (client_fifo_fd != -1) { if (read(client_fifo_fd, &my_data, sizeof(my_data)) > 0) { printf("received: %s\n", my_data.some_data); } close(client_fifo_fd); } } close(server_fifo_fd); unlink(client_fifo); exit(EXIT_SUCCESS); } 头文件:client.h #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <fcntl.h> #include <limits.h> #include <sys/types.h> #include <sys/stat.h> #define SERVER_FIFO_NAME "/tmp/serv_fifo" #define CLIENT_FIFO_NAME "/tmp/cli_%d_fifo" #define BUFFER_SIZE 20 struct data_to_pass_st { pid_t client_pid; char some_data[BUFFER_SIZE - 1]; }; |
|