基于多线程的并行TCP连接开发问题咨询及代码优化求助
你当前代码的互斥锁包裹了全部TCP建连、发送逻辑,多线程实际是串行执行的,这是吞吐量无提升的核心原因。以下是针对三个问题的具体解答:
1 如何验证线程是否在并行工作
- 打印时间戳:在每个线程
mq_timedreceive返回后、connect执行前、send执行完成后,都打印带毫秒/微秒级的时间戳和线程ID,若多个线程的执行时间段存在重叠,说明是并行执行;若所有线程的执行段完全错开,说明是串行执行。 - 抓包分析:用Wireshark过滤目标服务器IP,若同时存在多个不同源端口的TCP连接,且多个连接的数据包交错发送,说明线程在并行工作;若TCP连接是逐个建立、逐个发送完成后再建立下一个,说明实际是串行。
- 系统工具查看:获取程序进程ID后,执行
top -H -p <进程ID>,若多个middlemanThread线程同时处于R(运行)状态,说明正在并行执行。 - 临时删除互斥锁测试:你当前代码的互斥锁覆盖了全部业务逻辑,直接锁死了并行性,临时删除锁后再测吞吐量,若有明显提升就说明之前的锁导致了串行。
2 现有代码优化建议
- 缩小/删除互斥锁:你当前没有需要线程间互斥访问的可写共享资源,全局互斥锁完全是多余的,直接删除
pthread_mutex_lock和pthread_mutex_unlock即可,这是解决吞吐量问题的核心。 - 改用TCP长连接:不要每次发数据包都新建、关闭TCP连接,三次握手和四次挥手的开销占比很高,可以让每个线程初始化时就建立好和服务器的TCP连接,后续收到消息直接复用连接发送,大幅降低额外开销。
- 修复内存泄漏:你
calloc分配的income_buf、cast_buf从未释放,且cast_buf = income_buf直接覆盖了cast_buf的原始分配地址,导致这部分内存完全泄漏,按需释放内存,且不需要额外分配cast_buf,直接用income_buf做类型转换即可。 - 修复报文解析逻辑:当前
frag.packet_number = *cast_buf的写法是把单字节值赋值给int类型,会导致数据错误,直接用memcpy(&frag, income_buf, sizeof(fragma))即可完成结构体解析,不需要手动偏移指针。同时发送的报文大小直接用sizeof(fragma)即可,不需要手动累加各个成员的大小。 - 补全错误处理:对
socket、connect、send的返回值做完整判断,出错时及时关闭套接字、释放内存,避免文件描述符和内存泄漏。 - 删除无效延迟:代码末尾的
usleep(20000)没有任何意义,平白增加了20ms的处理延迟,直接删除即可。
3 单线程中打开多个套接字的实现方法
用IO多路复用技术即可实现单线程管理多个套接字,Linux环境下推荐用epoll,实现逻辑如下:
- 初始化阶段:预先创建N个TCP套接字,全部和目标服务器完成连接,设置为非阻塞模式。
- 创建epoll实例,将消息队列的文件描述符(可读事件)、所有TCP套接字的文件描述符(可写事件)加入epoll监听集合。
- 进入事件循环:
- 若消息队列触发可读事件:读取消息队列中的数据包,选择一个空闲的TCP套接字执行发送操作。
- 若TCP套接字触发可写事件:将之前未发送完成的剩余数据继续发送。
- 这种模式不需要线程切换开销,在IO密集型场景下性能通常优于多线程模式。
内容的提问来源于stack exchange,提问作者דן איטון
相关产品推荐
相关产品推荐

