有名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寫端(這裏還不是很清楚)