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
#include
#include
#include
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
int pipe(int file_description[2]); //操作成功返回0,失败返回-1.
file_description[2]有两个文件描述符组成的数值,从file_description[0]读管道数据,向file_description[1]中写数据。
#include
#include
#include
#include
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
int dup(int file_description);//打开一个新的文件描述符。
int dup2(int file_descritpion_one,int file_description_2);
#include
#include
#include
#include
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
#include
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
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
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
#include
#include
#include
#include
#include
#include
#include
#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];
};