目录
epoll LT模式实现的io多路转接 服务器端代码模板示例:
epoll ET模式实现的io多路转接 服务器端代码模板示例:
1. 端口复用
端口复用最常用用途:
- 防止服务器重启时之前绑定的端口还未释放
- 程序突然退出而系统没有释放端口
setsockopt函数
setsockopt函数有很多功能,这里只讲端口复用的功能。
#include <sys/types.h>
#include <sys/socket.h>
// 设置套接字属性
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
参数:
- sockfd: 要操作的文件描述符
- level: 级别 -> SOL_SOCKET (端口复用的级别)
- optname: 端口复用的级别(二选一,随便选,对于端口复用都可以)
- SO_REUSEADDR
- SO_REUSEPORT
- optval: 端口复用-> 对应的是整形数
- 1: 可以复用
- 0: 不能复用
- optlen: optval参数对应的内存大小
// 设置端口复用, 设置的时机: 服务器绑定端口之前, 设置端口复用。例如:
setsockopt();
bind();
2. IO多路转接
使用进程/线程方式实现并发:
- 共同点:
有一个父亲线程/进程 -> accept 某些情况下是阻塞的
子进程/子线程 -> 通信 -> read/write 某些情况下是阻塞的
- 不同点:
线程更节省系统资源, 一般写程序, 考虑线程的实现方式
在一个进程中, 调用另一个进程 -> exec
进程/线程方式实现并发代码模板:https://blog.csdn.net/qq_35883464/article/details/103643720
改进思路: 所有的阻塞状态, 程序猿都不去判断, 委托内核判断, 得到内核回复之后进行后续处理
- 程序猿是不能直接操作内核, 间接 -> 使用系统函数
- select
- poll
- epoll
IO多路转接核心思想: 不再由应用程序自己监视客户端连接和数据通信,取而代之由内核替应用程序监视文件。
2.1 select
select主旨思想:
- 先构造一张有关文件描述符的列表, 将要监听的文件描述符添加到该表中
- 调用一个函数,监听该表中的文件描述符,直到这些描述符表中的一个进行I/O操作时,该函数才返回。
- 函数对文件描述符的检测操作是由内核完成的
- 在返回时,它告诉进程有多少(哪些)描述符要进行I/O操作。
#include <sys/select.h>
#include <unistd.h>
// sizeof(fd_set) = 128
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
参数:
- nfds: 委托内核检测的最大文件描述符的值 + 1
- readfds: 读集合, 委托内核检测哪些文件描述符的读属性(读的是对方发送过来的数据)
- 传入传出的参数
- fd_set: 写集合, 委托内核检测哪些文件描述符的写属性
- 传入传出的参数
- 委托内核检测写缓冲区是不是还可以写数据(不满就可以写)
- exceptfds: 异常集合, 委托内核检测哪些文件描述符出现了异常
- 传入传出的参数
- timeout:
struct timeval {
long tv_sec; /* 秒 */
long tv_usec; /* 毫秒 */
};
- NULL: 永久阻塞, 直到检测到了文件描述符有变化
- tv_sec = 0, tv_usec = 0, 不阻塞
- tv_sec > 0 || tv_usec > 0, 阻塞对应的时间长度
返回值:
-1: 失败
>0(n): 检测的集合中有n个文件描述符发送的变化
// 将参数文件描述符fd对应的标志位, 设置为0
void FD_CLR(int fd, fd_set *set);
// 判断fd对应的标志位到底是0还是1, 返回值: fd对应的标志位的值, 0, 返回0, 1->返回1
int FD_ISSET(int fd, fd_set *set);
// 将参数文件描述符fd对应的标志位, 设置为1
void FD_SET(int fd, fd_set *set);
// fd_set 共有1024bit, 全部初始化为0
void FD_ZERO(fd_set *set);
select函数演示:
fd_set表是自己设置的,和文件描述符表一样。
值为1:要读的文件描述符。值为0:不关心的文件描述符。
之后,select会修改文件描述符表,值为1:要读的文件描述符有数据。值为0:不关心的文件描述符和没有数据的文件描述符。
io多路转接(select函数)服务器代码模板
图示代码流程:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/i