30 岁开发怕被优化?我靠转网安,把 “代码经验” 变成 “铁饭碗”
在网络编程中,如何高效处理多个客户端的并发连接是一个核心问题。
相比于多进程模型(Process-based),多线程模型(Thread-based)具有资源消耗更小、上下文切换更快的优势。
本文将基于课堂笔记,详细讲解如何将一个单进程的阻塞服务器改造为多线程并发服务器。
我们将重点解决线程参数传递中的“内存竞争”问题,并实现自动的资源回收。
设计思路
模型架构主线程(Main Thread):只负责监听连接。
循环调用accept(),一旦有客户端连接成功,就创建一个新的子线程。
子线程(Child Thread):负责具体的业务通信。
读取客户端数据,处理后回写。
2.
关键技术点线程分离(pthread_detach):主线程处于while(
循环中,无法调用pthread_join阻塞回收子线程资源。
因此,必须在子线程创建后立即设置为分离状态,让操作系统在线程结束时自动回收资源。
参数传递策略:这是本篇的难点。
❌错误做法:直接传递cfd的地址。
因为主线程循环很快,可能在子线程读取该地址前,主线程已经修改了该地址的内容(接受了新连接),导致多个线程操作同一个文件描述符。
✅正确做法:定义一个结构体数组。
为每个连接分配独立的存储空间(存放 fd 和 IP/Port 信息),将该结构体的指针传递给子线程。
核心代码实现我们需要定义一个结构体SockInfo来封装通信所需的数据,并创建一个全局数组来管理这些结构体。
数据结构定义// 定义最大连接数#defineMAX1024// 自定义结构体:存储文件描述符和客户端地址信息structSockInfo{intfd;// 通信文件描述符structsockaddr_inaddr;// 客户端地址信息pthread_ttid;// 线程ID (可选)};// 全局数组,用于存储每个子线程的连接信息structSockInfoinfos[MAX];
完整代码示例 (server_thread.c)#includestdio.h#includestdlib.h#includeunistd.h#includestring.h#includearpa/inet.h#includepthread.h#includeerrno.h#defineMAX1024#definePORT9999// 结构体定义structSockInfo{intfd;structsockaddr_inaddr;};// 全局数组structSockInfoinfos[MAX];// 子线程工作函数void*worker(void*arg){//
将参数强转回结构体指针structSockInfo*pinfo=(
17.c.13.nom-17.c-起草视在哪一-17.c.13.nom-17.c-起草视在哪一应用