云计算百科
云计算领域专业知识百科平台

Linux网络编程实战:手把手教你写一个多线程并发服务器

在网络编程中,如何高效处理多个客户端的并发连接是一个核心问题。相比于多进程模型(Process-based),多线程模型(Thread-based) 具有资源消耗更小、上下文切换更快的优势。

本文将基于课堂笔记,详细讲解如何将一个单进程的阻塞服务器改造为多线程并发服务器。我们将重点解决线程参数传递中的“内存竞争”问题,并实现自动的资源回收。

一、 设计思路

1. 模型架构

  • 主线程(Main Thread):只负责监听连接。循环调用 accept(),一旦有客户端连接成功,就创建一个新的子线程。
  • 子线程(Child Thread):负责具体的业务通信。读取客户端数据,处理后回写。

2. 关键技术点

  • 线程分离(pthread_detach):主线程处于 while(1) 循环中,无法调用 pthread_join 阻塞回收子线程资源。因此,必须在子线程创建后立即设置为分离状态,让操作系统在线程结束时自动回收资源。
  • 参数传递策略:这是本篇的难点。
    • ❌ 错误做法:直接传递 cfd 的地址。因为主线程循环很快,可能在子线程读取该地址前,主线程已经修改了该地址的内容(接受了新连接),导致多个线程操作同一个文件描述符。
    • ✅ 正确做法:定义一个结构体数组。为每个连接分配独立的存储空间(存放 fd 和 IP/Port 信息),将该结构体的指针传递给子线程。

二、 核心代码实现

我们需要定义一个结构体 SockInfo 来封装通信所需的数据,并创建一个全局数组来管理这些结构体。

1. 数据结构定义

// 定义最大连接数
#define MAX 1024

// 自定义结构体:存储文件描述符和客户端地址信息
struct SockInfo {


int fd; // 通信文件描述符
struct sockaddr_in addr; // 客户端地址信息
pthread_t tid; // 线程ID (可选)
};

// 全局数组,用于存储每个子线程的连接信息
struct SockInfo infos[MAX];

2. 完整代码示例 (server_thread.c)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <errno.h>

#define MAX 1024
#define PORT 9999

// 结构体定义
struct SockInfo {


int fd;
struct sockaddr_in addr;
};

// 全局数组
struct SockInfo infos[MAX];

// 子线程工作函数
void* worker(void* arg) {


// 1. 将参数强转回结构体指针
struct SockInfo* pinfo = (

赞(0)
未经允许不得转载:网硕互联帮助中心 » Linux网络编程实战:手把手教你写一个多线程并发服务器
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!