【发布时间】:2013-05-26 08:22:46
【问题描述】:
我正在编写使用 posix FIFO 进行通信的客户端-服务器应用程序。客户端和服务器都是单线程单进程应用程序。
服务器设计用于处理多个客户端。每个客户端都有自己的一对命名管道,一个用于从服务器向该客户端发送消息,另一个用于从客户端向服务器发送消息。
这个想法很简单,Server 循环遍历所有 Client 到 Server 管道并检查那里是否有要读取的内容。
我的第一个实现是这样的:
/* SERVER */
int desc = open(pipeName, O_RDONLY | O_NDELAY); //1
assert(desc > 0); //just simplyfing error handling
int read = read(desc, buffer, BUFSIZE); //2
if(read > 0)
do_stuff();
close(desc); //3
/* CLIENT */
int desc = open(pipeName, O_WRONLY) //4
assert(desc > 0); //just simplyfing error handling
int read = write(desc, buffer, BUFSIZE) //5
close(desc); //6
据我所知,此代码无效。
存在竞争条件,例如调用顺序如下:1、2、4、3、5、6 - 可能会导致 SIGPIPE。
问题在于,即使 PIPE 的另一端没有写入器,非阻塞读取打开总是成功的。 这意味着如果客户端将在 open() 上阻塞,则服务器执行非阻塞打开(这将解锁客户端),然后 read() 将返回 0,因为此时 PIPE 和之后的 close() 中将没有任何内容,那么当控制将返回想要在打开的 PIPE 上执行 write() 的客户端,这将导致 SIGPIPE,因为阅读器不再可用(服务器已经关闭了管道)。
目前我看到了两种解决方案:
- 使用“tryAgain()”在客户端处理 SIGPIPE - 这看起来很糟糕,如果我这样做,则无法保证它在任何时候都能正常工作 - 这取决于良好的命令处理顺序的可能性...
- 继续阅读 PIPE 在服务器中一直打开(打开一次并在连接被视为完成时关闭)- 这在我的应用程序架构中很不方便,但当然可以。我想它会解决问题,但我不确定。
这是我的问题:
- 这两种方法是否正确?
- 还有其他方法可以处理这种情况吗?
- 您认为第二种解决方案能正常工作吗?
- 您会选择什么?为什么?
感谢您的每一个回答。
【问题讨论】:
-
OT:应该是
assert(desc != -1);或assert(desc >= 0);,因为open()在错误时返回-1,在成功时返回非负整数。 -
不要编辑海报问题/代码。评论或回答错误的原因。
-
当你说它应该处理多个客户端时,你的意思是同时吗?因为您的代码一次只处理一个。处理 sigpipe 或“在服务器中一直打开读取管道”的任何更改都不会使其同时处理多个连接。
-
嗯,不是同时,但我希望它给人留下这样的印象。我的意思是 - 它可以遍历所有客户端并始终尽快处理准备好的客户端。
-
对那个编辑感到抱歉。你是对的。
标签: c client-server posix fifo sigpipe