48

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

在上述情况下,是否需要任何类型的锁定?

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

是否有任何开源库可以在上述情况下有所帮助?

4

3 回答 3

38

在上述情况下,是否需要任何类型的锁定?

没有任何。

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

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

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

不过,您可能希望记住 TCP 服务器的一个微妙问题……如果您的程序增长到可以处理多个客户端并需要定期进行一些内务处理。select使用带有超时的语句来检查侦听套接字的可读性是很自然和诱人的- 这表明客户端连接尝试 - 然后accept是连接。那里有一个竞争条件:客户端连接尝试可能在select()and之间下降accept(),在这种情况下,accept()如果侦听套接字不是非阻塞的,则会阻塞,这可能会阻止及时返回select()循环并暂停周期性的超时处理,直到另一个客户端连接。

是否有任何开源库可以在上述情况下有所帮助?

There are hundreds of libraries for writing basic servers, but ultimately what you've asked for is easily achieved atop OS-provided BSD sockets or their Windows bastardisation.

于 2012-10-23T05:01:54.150 回答
26

Sockets are BI-DIRECTIONAL. If you've ever actually dissected an Ethernet or Serial cable or seen the low-level hardware wiring diagram for them, you can actually SEE distinct copper wires for the "TX" (transmit) and "RX" (receive) lines. The software for sending the signals, from the device controller up to most OS APIs for a 'socket', reflects this and it is the key difference between a socket and an ordinary pipe on most systems (e.g. Linux).

To really get the most out of sockets, you need:
1) Async IO support that uses IO Completion Ports, epoll(), or some similar async callback or event system to 'wake up' whenever data comes in on the socket. This then must call your lowest-level 'ReadData' API to read the message off the socket connection.
2) A 2nd API that supports the low-level writes, a 'WriteData' (transmit) that pushes bytes onto the socket and does not depend on anything the 'ReadData' logic needs. Remember, your send and receive are independent even at the hardware level, so don't introduce locking or other synchronization at this level.
3) A pool of Socket IO threads, which blindly do any processing of data that is read from or will be written to a socket.
4) PROTOCOL CALLBACK: A callback object the socket threads have smart pointers to. It handles any PROTOCOL layer- such as parsing your data blob into a real HTTP request- that sits on top of the basic socket connection. Remember, a socket is just a data pipe between computers and data sent over it will often arrive as a series of fragments- the packets. In protocols like UDP the packets aren't even in order. The low-level 'ReadData' and 'WriteData' will callback from their threads into here, because it is where content-aware data processing actually begins.
5) Any callbacks the protocol handler itself needs. For HTTP, you package the raw request buffers into nice objects that you hand off to a real servlet, which should return a nice response object that can be serialized into an HTTP spec-compliant response.

Notice the basic pattern: You have to make the whole system fundamentally async (an 'onion of callbacks') if you wish to take full advantage of bi-directional, async IO over sockets. The only way to read and write simultaneously to the socket is with threads, so you could still synchronize between a 'writer' and 'reader' thread, but I'd only do it if the protocol or other considerations forced my hand. The good news is that you can get great performance with sockets using highly async processing, the bad is that building such a system in a robust way is a serious effort.

于 2014-02-15T19:12:17.583 回答
25

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

于 2012-10-23T00:11:26.073 回答