Linux : 创建一个简单的非阻塞服务器和客户端通过命名管道进行通信
Linux : Creating a simple non-blocking server and client to communicate over named pipes
我正在尝试创建命名管道 (FIFO) 的简单示例。在这里,服务器将侦听来自客户端的消息,该消息写入命名管道,对它们都是通用的。要实现的特殊之处在于 FIFO 应该是非阻塞的(使用 O_NONBLOCK
)。
所谓非阻塞,我的意思是如果没有reader,编写器应该在写入后立即return。同样,如果没有消息(没有作者),reader 应该立即 return。
虽然我已经创建了阻塞版本并且它工作正常。然后我试图将它转换为非阻塞。
这是客户:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#define FIFO "/tmp/myFIFO"
/*
This acts as the client, writing to the FIFO
*/
int main(int argc, char *argv[])
{
FILE *fp;
int fifo_fd;
if(argc != 2)
{
printf("Usage : ./fifo_client <message> \n");
exit(1);
}
fifo_fd = open(FIFO, O_WRONLY | O_NONBLOCK);
if(fifo_fd < 0)
{
perror("Error while open call");
exit(1);
}
fp = fdopen(fifo_fd, "w");
if(fp == NULL)
{
perror("Error while opening fd");
exit(1);
}
fputs(argv[1],fp);
/* Close the fp */
fclose(fp);
return 0;
}
这是服务器:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#define FIFO "/tmp/myFIFO"
/*
This acts as a server waiting for strings to be written by the client, over the FIFO
*/
int main()
{
FILE *fp;
int fifo_fd;
char buf[1024];
/* Create a FIFO */
umask(0);
if(mkfifo(FIFO,0666) < 0) /* 0666 is read and write permission*/
{
perror("Error creating FIFO");
exit(1);
}
while(1) /*endless wait, keep reading strings and print*/
{
fifo_fd = open(FIFO, O_RDONLY | O_NONBLOCK);
if(fifo_fd < 0)
{
perror("Error while open call");
exit(1);
}
fp = fdopen(fifo_fd, "w");
if(fp == NULL)
{
perror("Error while opening fd");
exit(1);
}
if(!fgets(buf,1024,fp))
printf("Nothing to read\n");
else
printf("Message Recieved : %s\n", buf);
fclose(fp);
sleep(1);
}
return 0;
}
我先运行服务器
其次,在第二个终端上,当我 运行 客户端时,出现错误:
Error while open call: No such device or address
我错过了什么?我做了man
,参数似乎是正确的。
编辑
将 open
和 close
调用移出 while 循环,完成了这项工作。但是现在如果在没有启动服务器的情况下启动客户端,则会抛出以下错误:
打开呼叫时出错:没有这样的设备或地址
文件 /tmp/myFIFO
存在于上次服务器执行的文件系统中,必须由客户端使用。
主要问题是循环打开和关闭文件。这是没有意义的。打开和关闭之间的时间间隔很短,您的客户必须击中它。它几乎没有机会这样做。 "No such device or address" 消息的发生正是因为客户端错过了文件打开的瞬间。这是主要问题。尝试将 open
、fopen
和 fclose
移出服务器循环。
您还 open
阅读但 fopen
写作,但我想这只是一个错字。这个组合不会运行。您需要将 fopen
的模式更改为 "r"
.
还有其他较小的问题。
- 您没有检查客户端中的错误。在您的程序中,客户端大多数时候会
open
失败,但有时打开会成功而写入会失败。
- 在此程序中使用
stdio
作为管道没有什么意义。 read
和 write
就可以了。
最后但同样重要的是,sleep
表明存在设计问题。事实上,在这个程序中阻塞 I/O 会更有意义。如果你只是想尝试非阻塞 I/O,那么使用 sleep
是可以的,但在实际程序中应该避免它。
我正在尝试创建命名管道 (FIFO) 的简单示例。在这里,服务器将侦听来自客户端的消息,该消息写入命名管道,对它们都是通用的。要实现的特殊之处在于 FIFO 应该是非阻塞的(使用 O_NONBLOCK
)。
所谓非阻塞,我的意思是如果没有reader,编写器应该在写入后立即return。同样,如果没有消息(没有作者),reader 应该立即 return。
虽然我已经创建了阻塞版本并且它工作正常。然后我试图将它转换为非阻塞。
这是客户:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#define FIFO "/tmp/myFIFO"
/*
This acts as the client, writing to the FIFO
*/
int main(int argc, char *argv[])
{
FILE *fp;
int fifo_fd;
if(argc != 2)
{
printf("Usage : ./fifo_client <message> \n");
exit(1);
}
fifo_fd = open(FIFO, O_WRONLY | O_NONBLOCK);
if(fifo_fd < 0)
{
perror("Error while open call");
exit(1);
}
fp = fdopen(fifo_fd, "w");
if(fp == NULL)
{
perror("Error while opening fd");
exit(1);
}
fputs(argv[1],fp);
/* Close the fp */
fclose(fp);
return 0;
}
这是服务器:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#define FIFO "/tmp/myFIFO"
/*
This acts as a server waiting for strings to be written by the client, over the FIFO
*/
int main()
{
FILE *fp;
int fifo_fd;
char buf[1024];
/* Create a FIFO */
umask(0);
if(mkfifo(FIFO,0666) < 0) /* 0666 is read and write permission*/
{
perror("Error creating FIFO");
exit(1);
}
while(1) /*endless wait, keep reading strings and print*/
{
fifo_fd = open(FIFO, O_RDONLY | O_NONBLOCK);
if(fifo_fd < 0)
{
perror("Error while open call");
exit(1);
}
fp = fdopen(fifo_fd, "w");
if(fp == NULL)
{
perror("Error while opening fd");
exit(1);
}
if(!fgets(buf,1024,fp))
printf("Nothing to read\n");
else
printf("Message Recieved : %s\n", buf);
fclose(fp);
sleep(1);
}
return 0;
}
我先运行服务器
其次,在第二个终端上,当我 运行 客户端时,出现错误:
Error while open call: No such device or address
我错过了什么?我做了man
,参数似乎是正确的。
编辑
将 open
和 close
调用移出 while 循环,完成了这项工作。但是现在如果在没有启动服务器的情况下启动客户端,则会抛出以下错误:
打开呼叫时出错:没有这样的设备或地址
文件 /tmp/myFIFO
存在于上次服务器执行的文件系统中,必须由客户端使用。
主要问题是循环打开和关闭文件。这是没有意义的。打开和关闭之间的时间间隔很短,您的客户必须击中它。它几乎没有机会这样做。 "No such device or address" 消息的发生正是因为客户端错过了文件打开的瞬间。这是主要问题。尝试将 open
、fopen
和 fclose
移出服务器循环。
您还 open
阅读但 fopen
写作,但我想这只是一个错字。这个组合不会运行。您需要将 fopen
的模式更改为 "r"
.
还有其他较小的问题。
- 您没有检查客户端中的错误。在您的程序中,客户端大多数时候会
open
失败,但有时打开会成功而写入会失败。 - 在此程序中使用
stdio
作为管道没有什么意义。read
和write
就可以了。
最后但同样重要的是,sleep
表明存在设计问题。事实上,在这个程序中阻塞 I/O 会更有意义。如果你只是想尝试非阻塞 I/O,那么使用 sleep
是可以的,但在实际程序中应该避免它。