在C或C ++中同时读取和写入同一个套接字

时间:2012-10-23 00:06:31

标签: c++ c linux sockets nonblocking

我正在实现一个简单的服务器,它接受单个连接,然后使用该套接字同时读取和写入来自读写线程的消息。 在Linux上的c / c ++中同时读取和写入相同套接字描述符的安全简便方法是什么? 我不需要担心从同一个套接字读取和写入多个线程,因为将有一个专用读取和单个专用写入线程写入套接字。

在上面的场景中,是否需要任何类型的锁定?

以上场景是否需要非阻塞套接字?

是否有任何开源库,这对上述场景有帮助?

3 个答案:

答案 0 :(得分:30)

  

在上面的场景中,是否需要任何类型的锁定?

无。

  

以上场景是否需要非阻塞套接字?

你可能担心的一点 - 已建立连接上的读写线程 - 如果你很高兴那些线程坐在那里等待完成,则不需要非阻塞。这通常是您使用线程而不是选择或轮询或异步操作的原因之一...也使代码更简单。

如果接受新客户的线程很乐意阻止拨打accept(),那么你也很好。

但是,您可能想要保留在脑后的TCP服务器存在一个微妙的问题...如果您的程序增长以处理多个客户端并且需要定期管理。使用带有超时的select语句检查侦听套接字的可读性(表示客户端连接尝试)然后accept连接是很自然和诱人的。那里存在竞争条件:客户端连接尝试可能在select()accept()之间下降,在这种情况下accept()将阻止侦听套接字不是非阻塞,并且可以阻止及时返回select()循环并停止定期开启超时处理,直到另一个客户端连接。

  

是否有任何开源库,这对上述场景有帮助?

有数百个用于编写基本服务器的库,但最终您所要求的内容很容易在操作系统提供的BSD套接字或其Windows混合之上实现。

答案 1 :(得分:17)

套接字是BI-DIRECTIONAL。如果您实际上已经剖析了以太网或串行电缆或看到了它们的低级硬件接线图,您实际上可以看到“TX”(发送)和“RX”(接收)线路的不同铜线。用于发送信号的软件,​​从设备控制器到大多数OS API用于“套接字”,反映了这一点,它是大多数系统(例如Linux)上套接字和普通管道之间的关键区别。 / p>

要真正充分利用插座,您需要:
1)Async IO支持使用IO完成端口,epoll()或某些类似的异步回调或事件系统,以便在数据进入套接字时“唤醒”。然后,必须调用最低级别的“ReadData”API以从套接字连接中读取消息。
2)支持低级写入的第二个API,一个将字节压入套接字的“WriteData”(传输),不依赖于“ReadData”逻辑所需的任何内容。请记住,即使在硬件级别,您的发送和接收也是独立的,因此请勿在此级别引入锁定或其他同步 3)一个Socket IO线程池,它盲目地处理从套接字读取或将被写入套接字的数据。
4)PROTOCOL CALLBACK:套接字线程具有智能指针的回调对象。它处理任何PROTOCOL层 - 例如将数据blob解析为真正的HTTP请求 - 位于基本套接字连接之上。请记住,套接字只是计算机之间的数据管道,通过它发送的数据通常会作为一系列片段(数据包)到达。在像UDP这样的协议中,数据包甚至不是​​有序的。低级“ReadData”和“WriteData”将从其线程回调到此处,因为它实际上是内容感知数据处理的开始。
5)协议处理程序本身需要的任何回调。对于HTTP,您将原始请求缓冲区打包到您传递给真实servlet的漂亮对象中,这些对象应该返回一个很好的响应对象,可以将其序列化为符合HTTP规范的响应。

请注意基本模式:如果您希望充分利用套接字上的双向异步IO,则必须使整个系统基本上处于异步状态(“回调的洋葱”)。同时读取和写入套接字的唯一方法是使用线程,因此您仍然可以在“编写器”和“读取器”线程之间进行同步,但是只有在协议或其他考虑因素强迫我的情况下我才会这样做。好消息是,使用高度异步处理的套接字可以获得很好的性能,不好的是,以健壮的方式构建这样的系统是一项非常重要的工作。

答案 2 :(得分:15)

你不必担心它。一个线程读取和一个线程写入将按预期工作。套接字是全双工的,因此您可以在写入时阅读,反之亦然。如果你有多个作家,你必须担心,但事实并非如此。