头文件 client.h
#include <unistd.h> #include <stdio.h> #include <stdlib.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]; };
服务器应用程序 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 ); //创建一个服务器fifo server_fifo_fd = open( SERVER_FIFO_NAME, O_RDONLY ); //以只读方式打开fifo if( -1 == server_fifo_fd ) { fprintf( stderr, "Server fifo failure\n" ); exit( EXIT_FAILURE ); } do { read_res = read( server_fifo_fd, &my_data, sizeof(my_data) ); //当客户端程序以写方式打开服务器fifo后,解除阻塞,开始读取数据 if( read_res>0 ) { 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); //将客户发送的client_pid提取出来,构成客户fifo的名称 client_fifo_fd = open( client_fifo, O_WRONLY ); //以只写的阻塞方式打开客户fifo if( -1 != client_fifo_fd ) { write( client_fifo_fd, &my_data, sizeof(my_data) ); //将数据写入客户fifo close( client_fifo_fd ); } } }while( read_res>0 ); close(server_fifo_fd); unlink(SERVER_FIFO_NAME); exit(EXIT_SUCCESS); }
客户程序client.c
#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( -1 == server_fifo_fd ) { fprintf(stderr, "Sorry, no server\n"); exit( EXIT_FAILURE ); } my_data.client_pid = getpid(); //获取当前库互进程的pid,作为发送数据的一部分,并且构成客户的fifo名称 sprintf(client_fifo, CLIENT_FIFO_NAME, my_data.client_pid); if( -1 == mkfifo(client_fifo, 0777 ) ) { fprintf(stderr, "Sorry, can't make %s\n", client_fifo ); exit( EXIT_FAILURE ); } for( times_to_send=0; times_to_send<5; times_to_send++ ) { //发送一次数据,读取一次服务器处理后的数据,连续循环5次 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( -1 != client_fifo_fd ) { 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); }
运行结果:
[zhang@localhost 客户服务器应用]$ ./server &
[1] 6048
[zhang@localhost 客户服务器应用]$ for i in 1 2 3 4 5
> do
> ./client &
> done
[2] 6055
[3] 6056
[4] 6057
[5] 6058
[6] 6059
[zhang@localhost 客户服务器应用]$ 6058 sent Hello from 6058, received: HELLO FROM 6058
6058 sent Hello from 6058, received: HELLO FROM 6058
6058 sent Hello from 6058, received: HELLO FROM 6058
6058 sent Hello from 6058, received: HELLO FROM 6058
6059 sent Hello from 6059, received: HELLO FROM 6059
6058 sent Hello from 6058, received: HELLO FROM 6058
6059 sent Hello from 6059, received: HELLO FROM 6059
6059 sent Hello from 6059, received: HELLO FROM 6059
6059 sent Hello from 6059, received: HELLO FROM 6059
6059 sent Hello from 6059, received: HELLO FROM 6059
6057 sent Hello from 6057, received: HELLO FROM 6057
6055 sent Hello from 6055, received: HELLO FROM 6055
6057 sent Hello from 6057, received: HELLO FROM 6057
6055 sent Hello from 6055, received: HELLO FROM 6055
6057 sent Hello from 6057, received: HELLO FROM 6057
6055 sent Hello from 6055, received: HELLO FROM 6055
6057 sent Hello from 6057, received: HELLO FROM 6057
6055 sent Hello from 6055, received: HELLO FROM 6055
6057 sent Hello from 6057, received: HELLO FROM 6057
6056 sent Hello from 6056, received: HELLO FROM 6056
6055 sent Hello from 6055, received: HELLO FROM 6055
6056 sent Hello from 6056, received: HELLO FROM 6056
6056 sent Hello from 6056, received: HELLO FROM 6056
6056 sent Hello from 6056, received: HELLO FROM 6056
6056 sent Hello from 6056, received: HELLO FROM 6056
[1] Done ./server
[2] Done ./client
[3] Done ./client
[4] Done ./client
[5]- Done ./client
[6]+ Done ./client
不同的客户请求交错在一起,但每个客户都获得了正确的服务器返回给它的处理数据。要注意的是客户请求的交错顺序是随机的。
服务器以只读模式创建它的 FIFO 并阻塞,直到第一个客户以写方式打开同一个 FIFO 来建立连接为止。此时,服务器进程解除阻塞。
与此同时,在客户打开了服务器 FIFO 后,它创建自己唯一的一个命名管道来读取服务器的返回的数据。完成这些工作后,客户发送数据给服务器(如果管道满就阻塞),然后阻塞在对自己的 FIFO 的read调用上。等待服务器的相应。
接收到来自客户的数据后,服务器处理它,然后以写方式打开客户管道并将处理后的数据返回,这将解除客户的阻塞状态。客户被解除阻塞后,它即可从自己的管道中读取服务器返回的数据。
整个过程不断重复,直到最后一个客户关闭服务器管道为止,这将使服务器的 read 调用失败,因为已经没有进程以写方式打开服务器管道了。