使用多个客户端的管道

时间:2013-05-25 17:04:08

标签: c

我正在尝试使用C对群组聊天系统的服务器端进行编程,而我的朋友正在编写客户端。对于服务器接收的每个客户端连接,它会分叉子进程以便处理客户端并继续接受任何可能的其他客户端。

服务器需要向所有当前连接的客户端发送所有在线用户(连接的客户端)的列表,因此我使用了管道。基本上,当创建子进程时,它通过套接字从客户端接收来自客户端的信息,并通过管道将这些信息发送给父进程,父进程保留所有客户端的列表。每次客户端进行更改(如开始聊天或断开连接)时,都必须更新此列表。例如,如果客户端断开连接,则子级通过管道向父级发送消息,并且父级对列表进行必要的操作以使其更新。请注意,为每个新连接创建管道。

我的问题是,例如,如果我一个接一个地接收3个连接,并且第二个子节点断开连接,则父节点不会从管道读取信息,因为这样的父节点与第二个子节点具有不同的管道。 (请记住,已创建新管道,因为已建立第3个连接)。我怎样才能解决这个问题?

我也试过创建一个公共管道,但是如果我在读/写之前没有关闭管道,我会收到错误,如果我关闭它们,当第二个客户端连接时我会收到分段错误,因为管道将被关闭

任何帮助都会非常感激,因为我一直在寻找数小时无济于事。

感谢。

1 个答案:

答案 0 :(得分:0)

父服务器进程知道创建子项的时间,因为它创建了子项。它可以通过设置SIGCLD信号处理程序来判断孩子何时死亡,以便在孩子死亡时通知孩子。 N th 孩子有N-1个管子要关闭 - 那些去其他孩子(除非有些孩子已经死亡)。父进程关闭它创建的管道的写端;子进程关闭它继承的管道的读取端(它将一个套接字留给客户端,并为它创建管道的写端以便与父进行通信)。

如果您需要知道孩子何时开始与客户沟通,那么您需要从孩子到父母的管道发送消息。如何判断孩子何时停止沟通并不是那么明显 - 在你宣布孩子再次闲置之前需要多长时间?

在父级中,您最终会在侦听套接字和所有读取管道上以某种形状或形式(select()poll()epoll())进行轮询。当某些活动发生时,父母会醒来并做出适当的反应。这是一个可行的设计,只要它不必扩展到数千或更多的客户端。它需要一些小心,特别是在关闭足够的文件描述符时。

你说:

  

我的问题是,例如,如果我一个接一个地接收3个连接,并且第二个子节点断开连接,则父节点不会从管道读取信息,因为这样的父节点与第二个子节点具有不同的管道。 (请记住,已创建新管道,因为已建立第3个连接)。我怎样才能解决这个问题?

父级应该有一个打开的文件描述符数组(打开管道以便读取各个子节点),以及指示管道另一端有哪个子节点(PID)。父级将在管道上获得EOF时关闭管道,或者当通知孩子已经死亡时(通过waitpid()或亲属)。轮询机制将告诉您管道何时关闭,至少是间接的(您将被告知文件描述符不会阻塞,然后您将获得EOF - 零字节读取)。

在您的场景中,父级有一个侦听套接字打开,另外3个读取文件描述符用于管道连接到3个子级(加上标准输入,输出和错误,也可能是syslog)。

虽然您可以使用来自所有孩子的单个管道,但处理起来要复杂得多。您必须确定哪个孩子在邮件中写下了每条邮件,确保邮件由孩子原子地编写。父母必须能够在任何时候告诉读取多少,以免混淆。单个管道的优点是对轮询系统调用执行的文件描述符操作较少;它也无限扩展(没有用完文件描述符)。

在任何情况下都不应该遇到核心转储问题。