You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于多线程的并行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,实现逻辑如下:

  1. 初始化阶段:预先创建N个TCP套接字,全部和目标服务器完成连接,设置为非阻塞模式。
  2. 创建epoll实例,将消息队列的文件描述符(可读事件)、所有TCP套接字的文件描述符(可写事件)加入epoll监听集合。
  3. 进入事件循环:
    • 若消息队列触发可读事件:读取消息队列中的数据包,选择一个空闲的TCP套接字执行发送操作。
    • 若TCP套接字触发可写事件:将之前未发送完成的剩余数据继续发送。
  4. 这种模式不需要线程切换开销,在IO密集型场景下性能通常优于多线程模式。

内容的提问来源于stack exchange,提问作者דן איטון

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 02:06:03