0

0

C++如何实现TCP服务器多线程处理连接_C++网络编程并发方案【工程】

尼克

尼克

发布时间:2026-02-16 15:56:54

|

506人浏览过

|

来源于php中文网

原创

直接用 std::thread 为每个连接创建线程易崩溃或泄漏,因线程未管理、client_fd 可能被提前关闭、频繁创建开销大;应托管线程生命周期、复制或移交 fd、设超时、用线程安全日志;线程池+epoll 更优,需非阻塞 fd 和安全队列。

c++如何实现tcp服务器多线程处理连接_c++网络编程并发方案【工程】

为什么不能直接用 std::thread 为每个连接起一个线程

看似最直白的方案——accept() 返回一个 client_fd,立刻 std::thread(handle_client, client_fd)——在工程中极易崩溃或泄漏。根本原因是:线程对象未被管理(比如忘记 join()detach()),且 client_fd 可能在线程启动前就被上层函数关闭;更严重的是,频繁创建/销毁线程开销大,连接突增时系统可能直接拒绝创建新线程(std::system_error with resource_unavailable_try_again)。

实操建议:

  • 必须对线程对象做生命周期托管:用 std::vector<:thread></:thread> 存储,并在服务器退出前统一 join();但仅靠这个还不够
  • 传入线程的 client_fd 必须复制(dup(client_fd))或确保主线程不再 close 它,否则可能出现“文件描述符被提前回收,子线程 read/write 失败”
  • 更稳妥的做法是:把 client_fd 移交给线程后,主线程立即 close() 原始 fd(前提是已 dup),避免资源滞留

pthread_createstd::thread 在 socket 场景下有本质区别吗

没有。底层都是调用 clone() 创建内核线程,std::thread 是 C++11 对 pthread 的封装。区别只在 RAII 和异常安全层面:std::thread 构造失败会抛 std::system_error,而 pthread_create 返回 int 错误码;std::thread 析构时若仍可 join 会调用 std::terminate(),而 pthread 不会自动 abort。

工程中建议坚持用 std::thread,但必须遵守两条铁律:

立即学习C++免费学习笔记(深入)”;

Grammarly
Grammarly

Grammarly是一款在线语法纠正和校对工具,伟大的AI辅助写作工具

下载
  • 构造后立即检查 t.joinable(),不 join 也不 detach 的线程对象不可析构
  • 处理 socket I/O 时,务必设置线程局部的 SO_RCVTIMEOSO_SNDTIMEO,否则阻塞读写会让整个线程卡死,无法响应中断或超时
  • 不要在线程函数里直接用 std::cout 打印日志——多线程并发写 stdout 可能乱序甚至崩溃,改用线程安全的 logger 或加 std::mutex 保护

线程池 + epoll 是不是更优?它和纯线程模型怎么衔接

是的,但不是“替代”,而是“分工”:主线程用 epoll_wait() 监听新连接和就绪事件,一旦 accept() 成功,就把新 client_fd 封装成任务,投递到线程池队列;工作线程从队列取任务,执行读、解析、响应、写全流程。

关键细节决定成败:

  • 线程池队列必须是无锁或带条件变量的线程安全队列,避免生产者/消费者竞争导致 fd 丢失
  • client_fd 投递前需设置为非阻塞(fcntl(fd, F_SETFL, O_NONBLOCK)),否则工作线程调用 read() 时仍可能阻塞,抵消线程池意义
  • 不要让工作线程再调用 epoll_ctl(ADD)——那是主线程职责;工作线程只负责同步 I/O,复杂协议(如 HTTP/1.1 管道)需自行维护连接状态机
  • 注意 epollEPOLLONESHOT 标志:启用后每次事件触发后需显式 epoll_ctl(MOD) 重新注册,否则后续数据来临时不会通知

实际部署时最容易被忽略的三个点

一是 ulimit -n 限制:每个连接至少占 2 个 fd(socket + 可能的 pipe/log),线程数 + 连接数总和很容易突破默认 1024,必须在启动脚本里设 ulimit -n 65536 并验证生效。

二是 TCP_DEFER_ACCEPTTCP_FASTOPEN 这类 socket 选项:它们能减少握手延迟和 SYN 队列压力,但需要内核支持(≥3.7 / ≥3.6),且客户端也要配合;不加不影响功能,但高并发下吞吐会明显下降。

三是 SIGPIPE 信号:当对端已关闭连接还调用 write(),默认会终止进程。必须在主线程初始化时调用 signal(SIGPIPE, SIG_IGN),否则任何一次意外断连都可能 kill 整个服务。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

750

2023.08.02

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

569

2024.08.29

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

234

2025.08.29

C++中int的含义
C++中int的含义

本专题整合了C++中int相关内容,阅读专题下面的文章了解更多详细内容。

209

2025.08.29

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

675

2023.08.10

Python 多线程与异步编程实战
Python 多线程与异步编程实战

本专题系统讲解 Python 多线程与异步编程的核心概念与实战技巧,包括 threading 模块基础、线程同步机制、GIL 原理、asyncio 异步任务管理、协程与事件循环、任务调度与异常处理。通过实战示例,帮助学习者掌握 如何构建高性能、多任务并发的 Python 应用。

346

2025.12.24

java多线程相关教程合集
java多线程相关教程合集

本专题整合了java多线程相关教程,阅读专题下面的文章了解更多详细内容。

25

2026.01.21

C++多线程相关合集
C++多线程相关合集

本专题整合了C++多线程相关教程,阅读专题下面的的文章了解更多详细内容。

24

2026.01.21

pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法
pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法

本专题系统整理pixiv网页版官网入口及登录访问方式,涵盖官网登录页面直达路径、在线阅读入口及快速进入方法说明,帮助用户高效找到pixiv官方网站,实现便捷、安全的网页端浏览与账号登录体验。

283

2026.02.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C# 教程
C# 教程

共94课时 | 9.6万人学习

C 教程
C 教程

共75课时 | 4.8万人学习

C++教程
C++教程

共115课时 | 18万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号