后台网络通信框架一般采用fifo来作为事件通知的机制:创建一个fifo,然后以非阻塞读和非阻塞写的方式打开fifo,然后把fd加到epoll里面,作为通知网络事件的fd.
在这里有个隐晦的问题容易被忽视.fifo在以非阻塞模式打开时,必须先打开读,然后打开写.不然会报错No such device or address.即如下代码所示是正确的
#define FIFO_FILE "/tmp/fifo.xxx" #define FIFO_MODE FILE_MODE S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH mkfifo(FIFO_FILE, FIFO_MODE); int readfd = open(FIFO_FILE, O_RDONLY | O_NONBLOCK, 0); int writefd = open(FIFO_FILE, O_WRONLY | O_NONBLOCK, 0);
上述代码中的两个open不能反过来,不然会报错: No such device or address
注意到这种情况,那即使以后我们写代码是在两个进程间通过fifo来通信,也不用关心以写的方式打开fifo之前,fifo是否已经以读的方式打开,因为我们可以设置一个dummy fd,如下所示:
int dummyfd = open(FIFO_FILE, O_RDONLY | O_NONBLOCK, 0); int writefd = open(FIFO_FILE, O_WRONLY | O_NONBLOCK, 0);
敢兴趣的朋友可以把下面的代码复制过去,看看输出结果:
1/注释L18
2/不注释L18
1 #include <unistd.h> 2 #include <sys/types.h> 3 #include <sys/stat.h> 4 #include <fcntl.h> 5 6 #include <errno.h> 7 #include <stdio.h> 8 #include <string.h> 9 10 #define FILE_MODE S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH 11 #define FIFO_FILE "/tmp/fifo.test_nonblock_write" 12 13 int main(void) 14 { 15 mkfifo(FIFO_FILE, FILE_MODE); 16 fprintf(stderr, "mkfifo, errno=%d, error=%s\n", errno, strerror(errno)); 17 18 //open(FIFO_FILE, O_RDONLY|O_NONBLOCK, 0); 19 fprintf(stderr, "open(O_RDONLY), errno=%d, error=%s\n", errno, strerror(errno)); 20 21 open(FIFO_FILE, O_WRONLY|O_NONBLOCK, 0); 22 fprintf(stderr, "open(O_WRONLY), errno=%d, error=%s\n", errno, strerror(errno)); 23 24 unlink(FIFO_FILE); 25 26 return 0; 27 }