2012-06-28 74 views
2

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

我主要关注TCP over IP行为,但知道它是否根据套接字协议而变化将会很有趣。

回答

4

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

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

1

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

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

你能做的仅仅是使用一个线程安全锁(互斥体)守护发送/写入套接字调用,只线程可以写在一个时间插槽上最简单的事情。

对于TCP,我会建议有一个专用线程来处理所有socket io。然后创建一个方法,让工作流中的消息可以异步地排队到套接字线程以供它发送。套接字线程也可以处理recv()调用,并在套接字连接被远程端终止时通知其他线程。

+0

我写信给来自2个不同进程的套接字,并且你遇到了我的问题:避免在进程之间传递消息(如果我有一个单独的写作进程)时,最好只是通过套接字发送它们。我可以将写入与信号同步,但如果内核无论如何都会这么做,我宁愿避免这种麻烦(这是我的问题的关键)。 – lvella

+0

我在试图找出sendto()是否是线程安全的时候遇到了这个答案。那是这种情况?如果是这样,太棒了! – fluffy

0

如果你尝试在超过了基础缓冲区大小流套接字发送大邮件,这几乎是保证你,你会得到一个简短的写 - 写,或者将通话将只写部分数据(尽可能将适合在缓冲区),然后返回记的金额,让你做的其余数据的另一个写入。

如果您在多个线程或进程中执行此操作,则每个写入(或发送)都将自动将一小部分消息原子地写入发送缓冲区,但随后的写入操作可能以任何顺序发生,结果是正在发送的大缓冲区将被交织。另一方面,如果您在DGRAM套接字上发送消息,则整个消息将以原子方式发送(作为单个第4层数据包,可能会被协议堆栈的较低层碎片化和重新组合),或者您会得到一个错误(EMSGSIZE Linux或其他UNIX变体)

+0

如果我们使用MSG_WAITALL标志写入大消息,该怎么办?这保证是原子吗? – FaceBro

+0

'MSG_WAITALL'不支持写入,只能读取。 –

+1

不,它可以用于读取和写入。 – FaceBro