TCP并发服务器:多进程 多线程 IO多路复用(select poll epoll)

TCP并发服务器

单循环服务器:一次只能处理一个客户端任务的服务器。

并发服务器:能够同时处理多个客户端任务的服务器。(一对多)

  • UDP服务端:具备并发性能
  • TCP服务端:建立连接,单循环服务器

TCP并发服务端四种实现方案

  1. 多进程 安全、资源开销大、并发量小

  2. 多线程 相对进程资源开销小,相对并发量大

  3. 线程池 多线程模型。提前创建好大量线程管理起来,避免反复创建线程带来时间消耗

    生产者--消费者 设计模式 主线程负责生产,线程池负责执行任务 任务队列

  4. IO多路复用 在不创建新进程/线程的前提下,使用一个进程同时监测多路IO

    文件 ---》fd 对多个文件描述符的监测,复用一个进程。 实现接口:select、poll、Epoll

多进程伪代码

复制代码
Socket();
Bind();
Listen();
While(1)
{
    Int connfd=accept();
    Pid_t pid=fork();
    If(pid>0)
    {

    }
    Else if(pid==0)
    {
        While(1)
        {
            Recv();
            Send();
        }
    }
}

多线程伪代码

复制代码
Socket();
Bind();
Listen();
While(1)
{
    Int  connfd=accept();
    Pthread_create();
    Pthread_datach();//分离属性
}

IO多路复用

在一个进程中,同时监测多个IO

select、poll、epoll

select

1)创建文件描述符集合(位图(数组)----》1024)

复制代码
fd_set fds;
FD_ZERO(&fds);

2)将要监测的文件描述符加入集合

复制代码
FD_SET(fd,&fds);

3)将集合传递给内核开始监测IO事件,并返回监测的结果

复制代码
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
select函数
复制代码
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

功能:通知内核监测文件描述符中的事件,并返回检测到的结果

参数

  • nfds :集合中最大的文件描述符+1
  • readfds:读事件的文件描述符集合
  • writefds:写事件的文件描述符集合
  • exceptfds:出错事件的文件描述符集合
  • timeout:超时时间
    • NULL :不设置超时时间(阻塞等待)

返回值

  • 成功:返回到达IO事件的个数
  • 失败:-1
  • 0:设置了超时时间,超时了还没有事件到达
配套宏函数
复制代码
void FD_CLR(int fd, fd_set *set);
//功能:将fd对应文件描述符清零

int FD_ISSET(int fd, fd_set *set);
//功能:判断fd对应的文件描述符是否存在

void FD_SET(int fd, fd_set *set);
//功能:将集合表中的fd对应的文件描述符加进去

void FD_ZERO(fd_set *set);
//功能:将集合表全部清零
select特点
  1. 使用数组(位图)保存文件描述符集合,最多允许监测1024个文件描述符;
  2. 将集合表创建在应用层,需要应用层和内核层的反复数据拷贝;
  3. 需要遍历寻找到达的IO事件,效率低;
  4. 只能工作在水平触发模式(低速模式),不能工作在边沿触发模式(高速模式);
poll特点
  1. 使用链表保存文件描述符集合,允许监测的文件描述符没有上限限制;
  2. 将集合表创建在应用层,需要应用层和内核层的反复数据拷贝;
  3. 需要遍历寻找到达的IO事件,效率低;
  4. 只能工作在水平触发模式(低速模式),不能工作在边沿触发模式(高速模式);
epoll特点
  1. 使用树形结构保存文件描述符集合(红黑树),允许监测的文件描述符没有上限限制,并且查找效率高;
  2. 将集合表直接创建在内核层,避免应用层和内核层的反复数据拷贝;
  3. 直接返回到达的事件,不需要应用层遍历查找;
  4. 可以工作在水平触发模式(低速模式),也可以工作在边沿触发模式(高速模式);

epoll使用步骤

  1. 创建文件描述符集合
  2. 添加文件描述符到集合
  3. 通知内核开始监测事件
epoll_create
复制代码
int epoll_create(int size);

功能 :创建文件描述符集合 参数

  • size:监测的文件描述符的最大上限 返回值
  • 成功:返回集合代表的文件描述符(句柄)
  • 失败:-1
epoll_ctl
复制代码
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

功能 :对epoll的文件描述符集合进行操作 参数

  • epfd:文件描述符集合
  • op:操作指令
    • EPOLL_CTL_ADD:添加
    • EPOLL_CTL_MOD:修改
    • EPOLL_CTL_DEL:删除
  • fd:需要操作的文件描述符
  • event:事件类型 返回值
  • 成功:0
  • 失败:-1
复制代码
typedef union epoll_data {
void *ptr;
int fd;  //要监测的文件描述符
uint32_t u32;
uint64_t u64;
} epoll_data_t;

struct epoll_event {
uint32_t events; /* Epoll events */
epoll_data_t data; /* User data variable */
};

events:事件类型

  • EPOLLIN:读事件
  • EPOLLOUT:写事件
epoll_wait
复制代码
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);

功能 :通知内核开始监测文件描述符集合并等待返回监测到的事件结果 参数

  • epfd:文件描述符集合
  • events:保存到达事件的集合
  • maxevents:监测的事件最大个数
  • timeout :超时时间
    • -1 :不设置超时,一直阻塞等待

返回值

  • 成功:返回到达事件的个数
  • 失败:-1
  • 0:超时时间到达,却没有事件返回

IO多路复用的应用场景

相关推荐
自养Agent8 分钟前
MCP Server Boundary Audit Report
linux·服务器·人工智能·windows·大模型·llm
Coisinier1 小时前
docker命令管理镜像及容器
linux·运维·nginx·docker·容器·操作系统
A心有千千结2 小时前
通过 SSH 反向代理让服务器借用本机网络访问 GitHub 的最佳实践
linux·服务器·网络·git·ssh·github
书生执笔画浮沉2 小时前
Linux 内核模块为什么不能自己解决兼容性问题?
linux·c·kernel·update·灵感
15Moonlight2 小时前
Linux网络(03):Socket 编程 TCP
linux·网络·tcp/ip
广州灵眸科技有限公司2 小时前
单芯片同时跑 Linux 与 RT-Thread:RV1126B的AMP异构方案完整拆解
linux·运维·服务器
小雪崩3 小时前
嵌入式学习:Linux驱动开发总结
linux·驱动开发·学习
C++ 老炮儿的技术栈3 小时前
std::atomic 是什么
linux·c语言·网络·c++·visual studio
2401_862880823 小时前
input 子系统框架 、platform 驱动框架
linux·驱动开发·嵌入式硬件
Liuqy-053 小时前
线程的互斥与同步机制——互斥锁、条件变量、无名信号量
linux·开发语言·线程·进程·条件变量·同步·互斥