使用fifo實現一個服務器端多個客戶端通信

有名fifo默認是阻塞讀,阻塞寫的,如果要設置阻塞屬性,可以再open()的時候進行設置

在阻塞情況下:實現服務器端可以不斷讀取客戶端寫到管道里面的文件流

這個裏面有個重要的問題時,如果使用服務器端進行read(),讀的buf的大小是多少呢?如果每一個客戶端每次傳過來的buf大小都不一樣,那麼服務器端使用read函數必然會造成數據讀取不完整或者超出實際寫進去的,這是因爲,對於多個進程都在向fifo文件中寫時,一個進程一個進程將要寫的內容寫進去,如果在讀buf大小的數據的時候,有兩個進程一前一後寫入數據(在下次read()之前),那麼這兩個進程的寫入數據就會混亂的讀入讀進程。

爲了解決這一問題:

關鍵:統一buf的大小,也就是write read函數每次操作的buf的大小都是確定的,這樣的話,每一個進程的數據就有了“原子性”,被封裝在一個buf中,保證每一次讀,都是一個完整的數據包

比如:

客戶端有登錄包,發送信息給其他客戶端的信息包等等,將不同包的內容封裝,這裏就像一個協議,不同的數據包有不同的編號,比如,登錄包,編號爲1,信息包編號爲2,這樣,講將要傳遞的內容拼接在一起,作爲長度固定的整體,如果長度不夠,填充特殊字符,就像ip數據報一樣,這樣,按照不同編號,服務器也對應了不同的解析buf的方法,這樣就保證多個進程的數據可以完整的傳遞到服務器端了

代碼:

client_0

#include <stdio.h>
#include <unistd.h>
#include <error.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>

#define BUF_SIZE 1024

void sys_err(char *errmes,int errno){
        perror(errmes);
        exit(errno);
}

int main(int argc ,char **argv){

        pid_t pid;
        int fd,i;
        char  buf[BUF_SIZE];
        if(argc<2){
                printf("usage:./client filename");
                exit(1);
        }
        if((fd=open(argv[1],O_WRONLY))<0){
                sys_err("open",3);
        }
        while(1){
                write(fd,"helloclient_0",13); //將buf的長度定爲13個字節
                sleep(1);
        }
        close(fd);
        return 0;
}

server.c

int main(int argc ,char **argv){

        pid_t pid;
        int fd,n;
        int buf[BUF_SIZE];
        if(argc<2){
                printf("usage:./server filename");
                exit(1);
        }
        //創建一個fifo
        //先判斷該文件是否存在,如果不存在再創建,存在就不創建了
        if(access(argv[1],F_OK)==-1){
                if(mkfifo(argv[1],0777)<0){
                        sys_err("mkfifo",2);
                }
        }
        //打開該fifo
        if((fd=open(argv[1],O_RDONLY))<0){
                sys_err("open",3);
        }
        //註冊信號
        signal(SIGCHLD,sig_child);
        //從fifo循環接收傳遞進來的數據
        while(1){
                if((n=read(fd,&buf,13))){   //read函數的buf也是13個字節
                        printf("%s\n",buf);
                }else{
                        continue;
                }
                sleep(1);
        }
        close(fd);
        return 0;
}

上面的兩段代碼,只是簡單的表示了一下文字的代碼形式,關於實際的協議定義,還需要推敲,並且buf的大小也要根據協議而定;對於不同的

協議,有不同的拼接填充方式以及解析方式,代碼中只是簡單實現了

1.使用mkfifo()函數新建一個fifo文件

2.使用open()打開函數打開該文件(可設置阻塞屬性)

3.向文件中讀寫

ps:如果只有一個讀端,並且先關閉讀端的話,寫端將進程也將結束

      如果先沒有fifo讀端,無法運行fifo寫端(這裏還不是很清楚)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章