Socket发送并发保证

时间:2012-06-28 02:41:14

标签: linux sockets

如果我在两个进程(或两个线程)之间共享一个套接字,并且在这两个进程中我尝试发送阻塞的大消息(大于下划线协议缓冲区),是否保证两个消息都将是按顺序发送?或者消息可以在内核中交错?

我主要对TCP over IP行为感兴趣,但知道它是否因套接字协议而异,这将会很有趣。

3 个答案:

答案 0 :(得分:5)

你问的是,如果你write()消息A,那么B在同一个套接字上,A是否保证在B之前到达?对于SOCK_STREAM(例如TCP)和SOCK_SEQPACKET(几乎从未使用过)套接字,答案是不合格的是。对于因特网上的SOCK_DGRAM(即UDP分组),答案是否定的:分组可以由网络重新排序。在单个主机上,unix域数据报套接字(在我知道的所有系统上)都会保留排序,但我不相信任何标准都能保证,我确信有边缘情况。

或等待:也许您在问这两个进程写的消息是否不会混合?是:单个系统调用(write / writev / sendto / sendmsg)始终以原子方式将其内容放入文件描述符中。但很明显,如果你或你的图书馆将这些写入分成多个电话,你将失去这种保证。

答案 1 :(得分:2)

对于UDP,如果两个线程同时写入套接字句柄,则两个消息将作为单独的数据报发送。如果数据包大于MTU,可能会发生IP分段,但结果数据报将被接收器保留并重新正确组装。换句话说,除了与UDP相关的正常问题(数据报重新排序,数据包丢失等等)之外,您对UDP是安全的。

对于基于流的TCP,我不知道。你的问题基本上是要求相当于“如果两个线程试图写入同一个文件句柄,文件是否仍然清晰可辨?”我实际上不知道答案。

您可以做的最简单的事情就是使用线程安全锁(mutex)来保护对套接字的发送/写入调用,这样只有线程才能一次写入套接字。

对于TCP,我建议使用专用线程来处理所有套接字io。然后只是发明一种方法,来自worker thrads的消息可以异步排队到套接字线程以便它发送。套接字线程也可以处理recv()调用,并在远程端终止套接字连接时通知其他线程。

答案 2 :(得分:0)

如果您尝试在超出底层缓冲区大小的STREAM套接字上发送大型消息,则几乎可以保证您将获得一个简短的写入 - 写入或发送调用将只写入部分数据(如就像在缓冲区中一样,然后返回写入的数量,让你为剩余数据做另一次写入。

如果你在多个线程或进程中执行此操作,那么每次写入(或发送)将以原子方式将一小部分消息写入发送缓冲区,但后续写入可能以任何顺序发生,结果是发送的大缓冲区将被交错。

另一方面,如果您在DGRAM套接字上发送消息,则整个消息将以原子方式发送(作为单层4数据包,可能会被协议堆栈的较低层碎片化并重新组装),或者您将得到一个错误(EMSGSIZE linux或其他UNIX变种)