Linux IO模型与并发服务器 学习笔记
阻塞IO用户层char buf[1024]; recv(fd, buf, sizeof(buf), 0);// 程序卡在这里等待数据内核1、检查socket接收缓冲区是否有数据2、若无数据•将进程状态设为TASK_INTERRUPTIBLE可中断睡眠•进程从CPU运行队列移出触发调度器切换其他进程运行3、数据到达•网卡触发硬件中断→ 内核将数据拷贝到接收缓冲区•唤醒进程状态改为TASK_RUNNING重新加入运行队列非阻塞IO函数原型int fcntl(int fd, int cmd, ... /* arg*/ );用户层fcntl(fd, F_SETFL, O_NONBLOCK); // 设置非阻塞标志 while (1) { int n recv(fd, buf, sizeof(buf), 0); if (n 0) break; // 数据就绪 if (errno ! EAGAIN) exit(1); // 错误处理 usleep(1000); // 避免CPU占满 }1、检查接收缓冲区无论是否就绪都立即返回结果2、无数据时返回EAGAIN错误码进程继续执行不进入睡眠IO多路复用IO多路复用是一种单线程或单进程管理多个文件描述符如套接字的技术核心是通过系统调用监视多个IO操作的状态当某个IO操作就绪可读、可写或发生异常时通知应用程序进行处理selectselect函数头文件#include sys/socket.h #include sys/types.h函数原型int select(int nfds, fd_set*readfds, fd_set*writefds,fd_set*exceptfds, struct timeval*timeout);参数•nfds要监视的最大的文件描述符1•readfds要监视的读文件描述符集合如果不关心可以传NULL•writefds要监视的写文件描述符集合如果不关心可以传NULL•exceptfds要监视的异常文件描述符集合如果不关心可以传NULL•timeout超时时间如果是NULL表示永久阻塞返回值成功返回返回就绪的文件描述符的个数失败返回-1并重置错误码pollpoll函数头文件#include sys/socket.h #include sys/types.h函数原型int poll(struct pollfd*fds, nfds_tnfds, int timeout);参数•fds一个指向pollfd结构体数组的指针它描述了要监视的文件描述符及其事件•nfdsfds数组中有效描述符元素的数量•timeout是等待时间单位为毫秒返回值成功返回结构体中revents域不为0的文件描述符个数如果在超时前没有任何事件发生poll()返回0失败返回-1并重置错误码IO多路复用并发服务器服务器模型服务器模型有两种循环服务器、并发服务器循环服务器:循环服务器在同一个时刻只能响应一个客户端的请求并发服务器:并发服务器在同一个时刻可以响应多个客户端的请求TCP服务器默认的就是一个循环服务器因为有两个阻塞的函数accept和recv之间相互影响UDP服务器默认的就是一个并发服务器因为只有一个阻塞的函数recvfrom多线程并发服务器实现原理流程主线程创建监听Socket → bind() → listen()while (1) {accept()接收新连接→ 创建子线程处理连接}子线程recv()/send()处理客户端请求close()关闭连接实现原理fork()模型•主进程监听连接子进程处理请求•父子进程完全独立崩溃互不影响预fork优化•启动时预先创建多个子进程类似Apache•通过共享监听socketSO_REUSEPORT实现负载均衡主进程•1.创建监听Socket → bind() → listen()•2. while (1) {accept()接收新连接→ fork()创建子进程处理连接}子进程•1. close()关闭监听Socket继承自父进程•2. recv()/send()处理客户端请求•3. exit()退出IO多路复用并发服务器主线程1.创建监听Socket → bind() →listen()2.初始化fd_set集合将监听Socket加入集合3. while (1) {select()监听所有fd →返回就绪的fd数量for (每个就绪的fd) {if (是监听Socket) →accept()新连接并加入fd_setelse → recv()/send()处理数据}}pollfd结构体struct pollfd { int fd; // 文件描述符 short events; // 等待的事件 short revents; // 实际发生的事件 };事件类型常值说明读事件POLLIN普通或优先带数据可读POLLPRI高优先级数据可读写事件POLLOUT普通或优先带数据可写POLLWRNORM普通数据可写错误事件POLLERR发生错误POLLHUP发生挂起POLLNVAL描述符不是打开的文件TCP/IP协议常见协议头分析TCP/IP协议网络封包格式源端口16bit目的端口16bit序号32bit确认号32bit源IP地址32bit数据偏移4bit保留(6bit)URGACKPSHPSHSYNFIN窗口16bit校验和16bit紧急指针16bit选项长度可变填充版本号首部长度服务类型TOS总长度标识标志位片偏移生存时间TTL协议首部检验和源IP地址目的IP地址选项字段长度可变填充数据TCP/IP协议数据封装过程抓包工具wireshark的使用TCP沾包问题及解决方案TCP沾包问题TFTP协议TFTP协议格式TFTP通讯流程TFTP文本传输