socket套接字在多线程发送数据时要加锁吗?

转自知乎


问题:一条报文在1000字节到4000字节之间,数据量在每秒5000左右,多线程写套接字,要加锁吗?没有加锁会导致报文错乱吗?在网络编程的时候,报文不超过MTU是否就无需对套接字加锁?


解答①:
你连 UDP 还是 TCP 都没说。


对于 UDP,多线程读写同一个 socket 不用加锁,不过更好的做法是每个线程有自己的 socket,避免 contention,可以用 SO_REUSEPORT 来实现这一点。
对于 TCP,通常多线程读写同一个 socket 是错误的设计,因为有 short write 的可能。假如你加锁,而又发生 short write,你是不是要一直等到整条消息发送完才解锁(无论阻塞IO还是非阻塞IO)?如果这样,你的临界区长度由对方什么时候接收数据来决定,一个慢的 peer 就把你的程序搞死了。


总结:对于 UDP,加锁是多余的;对于 TCP,加锁是错误的。


作者:陈硕
链接:https://www.zhihu.com/question/56899596/answer/150926723
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。


解答②:
已经有陈硕大神镇楼了,腆颜说几句。很多网络库和框架其实已经向我们提供了最佳实践,应用中的所有socket都应该是异步非阻塞且只在一个事件循环(一般还会一个线程只有一个事件循环)中进行数据io,多线程io一个socket加不加锁都是非主流的做法


解答③:
对于TCP,正确的做法是,创建一个单独的发送线程,让发送线程统一发送数据。例如你的工作线程池处理完了业务task,你把需要回复的包封装成一个发送task,包含发送套接字和消息,丢给发送线程就行了。


对于UDP,它是面向报文的是一个完整的报文接一个完整的报文的,不需要加锁,在UNP中也提到过一个发送就是一个原子操作。其实我们从UDP的接收都可以看的出来,UDP接收的时候需要设置接收缓冲大于报文大小,并且每次从接收缓冲都是只能取回一个完整的包,不需要处理粘包,半包。首先是说了UDP协议栈会在发送的时候分片,到了接收重组,每次组好了完整的包就丢给用户,不完整就丢掉。其次说明了协议栈是以报文整个的形式来传递,所以是原子操作,“线程安全”。


作者:coding man
链接:https://www.zhihu.com/question/56899596/answer/248122959
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

猜你喜欢

转载自blog.csdn.net/hemeinvyiqiluoben/article/details/80392976
今日推荐