先来了解一下为什么要设计TCP并发服务器:
1.TCP并发服务器问题:
当一个服务器需连接多个客户端时,服务器需要使用accept等待三次握手连接请求,同时还需要RECV等待接收所有的客户端发送数据,但是这两个函数接口本身都具有阻塞功能,所以我们的常规方法已经无法解决目前的问题了
2.解决方法:
1.TCP并发服务器线程模型:
每有一个客户端连接,服务器就创建一个线程,去进行数据的交互,线程结束自动回收
弊端:
- 线程调度资源开销较大
- 栈空间有限,无法同时支持大量线程调度(无法同时连接多个客户端(最多200多个))
2.TCP并发服务器多路复用模型:
- 利用循环加一个阻塞效果更强的接口,每次循环只执行一个阻塞接口的操作,达到并发的效果

3.Linux操作系统中的4种IO
1.阻塞IO
- 执行效率高,数据没来时,cpu阻塞等待,不会占用cpu资源
2,非阻塞IO
- 执行效率较低,CPU需要轮询判断是否有IO事件发生,资源开销比较大
3.异步IO
- 当内核检测到有对应IO事件发生时(标记套接字文件有数据写入)会主动向应用层上报信号事件
- 定义的接收信号进程,会捕捉信号执行对应内容
4.多路复用IO
- 用一个函数接口监听多个文件描述符是否产生IO事件(文件描述符的状态发生变化),只要文件描述符组中有一个产生IO事件,则不再阻塞,将其他文件描述符移出,执行当前内容
3.函数接口:
1.fcntl
原型:int fcntl(int fd,int cmd,···/arg /)
功能:
- 向文件描述符发生cmd命令;
参数:
- fd:文件描述符
- cmd:
- F_GETFL:获得属性
- F_SETFL:设置属性
返回值:
- 成功返回0
- 失败返回-1
非阻塞指令设置
flags = fcntl(fd,F_GETFL); //获取原本属性
flags |= O_NOBLOCK //给原本属性添加非阻塞属性
fcntl(fd,F_SETFL,flags); /设置非阻塞属性
异步IO指令设置:
flags = fcntl(fd,F_GETFL) //获取原本属性
flags |= O_ASYNC //给原本属性添加异步属性
fcntl(fd,F_SETFL,flags) //给文件描述符设置异步属性
fcntl(fd,F_SETOWN,getpid()) //设置pid 对应的进程接收fd 发送的SIGIO信号
多路复用IO函数接口:
1.select
原型:
- int select(int nfds,fd_set *readfds,fd_set *writefds,fd_set *exceptfds,struct timeout *timeout)
select相关函数:
1.void FD_CLR(int nfds,fd_set *set)
功能:将文件描述符fd,从文件描述符组中移除;
2.int FD_ISSET(int fd,fd_set *set)
功能:判断文件描述符fd,是否在文件描述符组中;
3.void FD_SET(int fd,fd_set *set)
功能:将文件描述符fd,添加进文件描述符组中;
4.void FD_ZERO(fd_set *set)
功能:将文件描述符组清零
功能:
- 监听文件描述符组中是否有事件发生
参数:
- nfds:最大的文件描述符+1;
- readfds:读文件描述符集合
- writefds:写文件描述符集合
- except:其他文件描述符集合
- timeout:超时时间,穿NULL表示一直阻塞
返回值:
- 成功返回产生事件的文件描述符个数
- 失败返回-1;
- 超时返回0;