Linux 在 C 或 C++ 中在同一个套接字上同时读写

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13021796/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 17:34:28  来源:igfitidea点击:

simultaneously read and write on the same socket in C or C++

c++clinuxsocketsnonblocking

提问by Jimm

I am implementing a simple server, that accepts a single connection and then uses that socket to simultaneously read and write messages from the read and write threads. What is the safe and easy way to simultaneously read and write from the same socket descriptor in c/c++ on linux? I dont need to worry about multiple threads read and writing from the same socket as there will be a single dedicated read and single dedicated write thread writing to the socket.

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

In the above scenario, is any kind of locking required?

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

Does the above scenario require non blocking socket?

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

Is there any opensource library, that would help in the above scenario?

是否有任何开源库可以帮助解决上述情况?

采纳答案by Tony Delroy

In the above scenario, is any kind of locking required?

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

None.

没有任何。

Does the above scenario require non blocking socket?

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

The bit you're probably worried about - the read and write threads on an established connection - do not need to be non-blocking if you're happy for those threads to sit there waiting to complete. That's normally one of the reasons you'd use threads rather than select or poll or async operations... keeps the code simpler too.

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

If the thread accepting new clients is happy to block in the call to accept(), then you're all good there too.

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

Still, there's one subtle issue with TCP servers you might want to keep in the back of your mind... if your program grows to handle multiple clients and have some periodic housekeeping to do. It's natural and tempting to use a selectstatement with a timeout to check for readability on the listening socket - which indicates a client connection attempt - then acceptthe connection. There's a race condition there: the client connection attempt may have dropped between select()and accept(), in which case accept()will block if the listening socket's not non-blocking, and that can prevent a timely return to the select()loop and halt the periodic on-timeout processing until another client connects.

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

Is there any opensource library, that would help in the above scenario?

是否有任何开源库可以帮助解决上述情况?

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.

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

回答by mfontanini

You don't have to worry about it. One thread reading and one thread writing will work as you expect. Sockets are full duplex, so you can read while you write and vice-versa. You'd have to worry if you had multiple writers, but this is not the case.

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

回答by Zack Yezek

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).

套接字是双向的。如果您曾经真正剖析过以太网或串行电缆,或者看过它们的低级硬件接线图,您实际上可以看到“TX”(发送)和“RX”(接收)线的不同铜线。用于从设备控制器到“套接字”的大多数操作系统 API 发送信号的软件反映了这一点,这是大多数系统(例如 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.

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

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.

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