为什么要使用select模型?
答:解决基本C/S模型中,accept()、recv()、send()阻塞的问题
select模型与C/S模型的不同点
C/S模型中accept()会阻塞一直傻等socket来链接
select模型只解决accept()傻等的问题,不解决recv(),send()执行阻塞问题
其实select模型解决了实现多个客户端链接,与多个客户端分别通信
两个模型都存在recv(),send()执行阻塞问题
由于服务器端,客户端不需要(客户端只有一个socket,可以通过加线程解决同时recv和send)
select模型逻辑
将所有的socket(服务器端+客户端)装进一个数组中
通过select()遍历socket数组
取出有相应的socket放进另一个数组(都是有响应的socket)
对装有响应的socket数组集中处理
服务器socket响应:客户端链接,调用accept()
客户端socket响应:客户端通信,调用send()或recv()
图片描述
select()
fd_set
作用:定义一个用来装socket的结构体
#ifndef FD_SETSIZE
#define FD_SETSIZE 64 /默认64个/
#endif /* FD_SETSIZE */
typedef struct fd_set {
u_int fd_count; /* how many are SET? /
SOCKET fd_array[FD_SETSIZE]; / an array of SOCKETs */
} fd_set;
默认装socket大小为64,可以通过在winsock2.h头文件前声明宏,给一个更大的值
#define FD_SETSIZE 128
#include <WinSock2.h>
因为原理就是不停遍历检测,越多效率越低,延迟越大,所以合适大小最好。
select模型应用,就是小用户量访问。
四个操作fd_set的操作宏
操作宏 作用 代码
FD_ZERO 将客户端socket集合清零 FD_ZERO(&clientSockets);
FD_SET 添加一个socket(超过默认值大小不再处理) FD_SET(socketListen,&clientSockets);
FD_CLR 从集合中删除指定的socket,一定要close,手动释放 FD_CLR(socketListen, &cli