In a multi-thread code, if there are several threads trying to send data to a tcp socket at the same time, what will happen? will their data be mixed or will different threads will end up sending data one by one?
在多线程代码中,如果有几个线程同时向tcp套接字发送数据,会发生什么?它们的数据是混合的,还是不同的线程会逐一发送数据?
2 个解决方案
#1
6
It depends upon which primitives you're using to submit data to the socket.
这取决于您要使用哪些原语向套接字提交数据。
If you're using write(2)
, send(2)
, sendto(2)
, or sendmsg(2)
and the size of your message is small enough to fit entirely within the kernel buffers for the socket, then that entire write will be sent as a block without other data being interspersed.
如果您使用的是write(2)、send(2)、sendto(2)或sendmsg(2),并且消息的大小足够小,可以完全符合套接字的内核缓冲区,那么整个写入将作为一个块发送,而没有其他数据被散布。
If you're using fwrite(3)
(or any other higher-level buffered IO abstraction), then there is a chance that your data will be sent without any other data being interspersed, but I would not rely upon this behavior.
如果您正在使用fwrite(3)(或任何其他高级缓冲IO抽象),那么您的数据有可能在没有任何其他数据穿插的情况下被发送,但我不会依赖这种行为。
I can't speak to sendfile(2)
behavior. I'd like to think that the sendfile(2)
operation "writes" the entire contents of the file to the socket before any other write(2)
requests on the socket, but the documentation I've read doesn't say a word about it, so you better not make the assumption that it is in any sense "atomic".
我无法与sendfile(2)行为对话。我想认为sendfile(2)操作“写”的全部内容文件到套接字之前其他写(2)套接字的请求,但是我读过的文档没有说一个字,所以你最好不要假设它是在任何意义“原子”。
The safest mechanism is for only a single thread to ever be submitting data to a socket.
最安全的机制是只有一个线程向套接字提交数据。
#2
-1
Indeed as the previous answer says: "The safest mechanism is for only a single thread to ever be submitting data to a socket."
正如前面的回答所言:“最安全的机制是只有一个线程向套接字提交数据。”
But if you want to have multiple threads call read/write, you must guarantee thread safety yourself. I've written a wrapper around send and recv below that does this for you.
但是,如果您想让多个线程调用读/写,您必须自己保证线程安全。我已经写了一个关于发送和recv的包装器,它为您做这个。
Send() and Recv() are thread safe in the sense that they wont cause a crash, but there is no guarantee that that data wont be "intermixed" with data sent from other threads. Since we most likely don't want that, we must block until all the thread's data is confirmed sent or received, or errored out. Such a long blocking call can be problematic, so make sure you're doing this on threads that can handle long blocking operations.
Send()和Recv()在不会导致崩溃的意义上是线程安全的,但是不能保证数据不会与来自其他线程的数据“混合”。由于我们很可能不希望这样,所以我们必须阻塞,直到所有线程的数据被确认发送或接收,或者出错为止。如此长的阻塞调用可能会有问题,所以请确保您是在能够处理长阻塞操作的线程上执行此操作。
For linux:
linux:
#include <sys/types.h>
#include <sys/socket.h>
#include <map>
#include <mutex>
/* blocks until the full amount of bytes requested are read
* thread safe
* throws exception on error */
void recv_bytes(int sock, char* buf, int len, int flags){
static std::map<int, std::mutex> mtx;
std::lock_guard<std::mutex> lock(mtx[sock]);
int bytes_received = 0;
while (bytes_received != len){
int bytes = recv(sock, buf + bytes_received, len - bytes_received, flags);
//error check
if (bytes == -1){
throw std::runtime_error("Network Exception");
}
bytes_received += bytes;
}
}
/* blocks until the full amount of bytes requested are sent
* thread safe
* throws exception on error */
void send_bytes(int sock, char* buf, int len, int flags){
static std::map<int, std::mutex> mtx;
std::lock_guard<std::mutex> lock(mtx[sock]);
int bytes_sent = 0;
while (bytes_sent != len){
int bytes_s0 = send(sock, buf, len, flags);
if (bytes_sent == -1) {
throw std::runtime_error("Network Exception");
}
bytes_sent += bytes_s0;
}
}
#1
6
It depends upon which primitives you're using to submit data to the socket.
这取决于您要使用哪些原语向套接字提交数据。
If you're using write(2)
, send(2)
, sendto(2)
, or sendmsg(2)
and the size of your message is small enough to fit entirely within the kernel buffers for the socket, then that entire write will be sent as a block without other data being interspersed.
如果您使用的是write(2)、send(2)、sendto(2)或sendmsg(2),并且消息的大小足够小,可以完全符合套接字的内核缓冲区,那么整个写入将作为一个块发送,而没有其他数据被散布。
If you're using fwrite(3)
(or any other higher-level buffered IO abstraction), then there is a chance that your data will be sent without any other data being interspersed, but I would not rely upon this behavior.
如果您正在使用fwrite(3)(或任何其他高级缓冲IO抽象),那么您的数据有可能在没有任何其他数据穿插的情况下被发送,但我不会依赖这种行为。
I can't speak to sendfile(2)
behavior. I'd like to think that the sendfile(2)
operation "writes" the entire contents of the file to the socket before any other write(2)
requests on the socket, but the documentation I've read doesn't say a word about it, so you better not make the assumption that it is in any sense "atomic".
我无法与sendfile(2)行为对话。我想认为sendfile(2)操作“写”的全部内容文件到套接字之前其他写(2)套接字的请求,但是我读过的文档没有说一个字,所以你最好不要假设它是在任何意义“原子”。
The safest mechanism is for only a single thread to ever be submitting data to a socket.
最安全的机制是只有一个线程向套接字提交数据。
#2
-1
Indeed as the previous answer says: "The safest mechanism is for only a single thread to ever be submitting data to a socket."
正如前面的回答所言:“最安全的机制是只有一个线程向套接字提交数据。”
But if you want to have multiple threads call read/write, you must guarantee thread safety yourself. I've written a wrapper around send and recv below that does this for you.
但是,如果您想让多个线程调用读/写,您必须自己保证线程安全。我已经写了一个关于发送和recv的包装器,它为您做这个。
Send() and Recv() are thread safe in the sense that they wont cause a crash, but there is no guarantee that that data wont be "intermixed" with data sent from other threads. Since we most likely don't want that, we must block until all the thread's data is confirmed sent or received, or errored out. Such a long blocking call can be problematic, so make sure you're doing this on threads that can handle long blocking operations.
Send()和Recv()在不会导致崩溃的意义上是线程安全的,但是不能保证数据不会与来自其他线程的数据“混合”。由于我们很可能不希望这样,所以我们必须阻塞,直到所有线程的数据被确认发送或接收,或者出错为止。如此长的阻塞调用可能会有问题,所以请确保您是在能够处理长阻塞操作的线程上执行此操作。
For linux:
linux:
#include <sys/types.h>
#include <sys/socket.h>
#include <map>
#include <mutex>
/* blocks until the full amount of bytes requested are read
* thread safe
* throws exception on error */
void recv_bytes(int sock, char* buf, int len, int flags){
static std::map<int, std::mutex> mtx;
std::lock_guard<std::mutex> lock(mtx[sock]);
int bytes_received = 0;
while (bytes_received != len){
int bytes = recv(sock, buf + bytes_received, len - bytes_received, flags);
//error check
if (bytes == -1){
throw std::runtime_error("Network Exception");
}
bytes_received += bytes;
}
}
/* blocks until the full amount of bytes requested are sent
* thread safe
* throws exception on error */
void send_bytes(int sock, char* buf, int len, int flags){
static std::map<int, std::mutex> mtx;
std::lock_guard<std::mutex> lock(mtx[sock]);
int bytes_sent = 0;
while (bytes_sent != len){
int bytes_s0 = send(sock, buf, len, flags);
if (bytes_sent == -1) {
throw std::runtime_error("Network Exception");
}
bytes_sent += bytes_s0;
}
}