使用 FIFO 的客户/服务器应用程序示例

来源:互联网 发布:淘宝定价规则 编辑:程序博客网 时间:2024/06/06 04:21

头文件 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 20struct 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 调用失败,因为已经没有进程以写方式打开服务器管道了。

0 0