一、select模型:
select(
_In_ int nfds,
_Inout_opt_ fd_set FAR * readfds,
_Inout_opt_ fd_set FAR * writefds,
_Inout_opt_ fd_set FAR * exceptfds,
_In_opt_ const struct timeval FAR * timeout
);//第一个参数在windows没有意义,在其他系统中是fd_set中所有描述符socket的范围+1,第二到第四个参数分别为可读、可写、异常的文件描述符集合地址,最后一个参数为时间设置(成为非阻塞的关键)
取fd_set长度为1字节,fd_set中的每一bit可以对应一个文件描述符fd。则1字节长的fd_set最大可以对应8个fd。
执行FD_ZERO(&set);则set用位表示是0000,0000。
若fd=5,执行FD_SET(fd,&set);后set变为0001,0000(第5位置为1)
若再加入fd=2,fd=1,则set变为0001,0011(表示要被监控的文件)
执行select(6,&set,0,0,0)阻塞等待(因为最大的描述符为5,因此传入6)
若fd=1,fd=2上都发生可读事件,则select返回,此时set变为0000,0011,将没有发生改变的都清零
struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* and microseconds */
};//第一个参数为秒,第二个参数为毫秒
服务器改进:
while (true) {
fd_set fdRead;
FD_ZERO(&fdRead);
FD_SET(sock, &fdRead);
for (int i = 0; i < clients.size(); i++)
FD_SET(clients[i], &fdRead);
timeval t = {5,0};
int ret = select(0, &fdRead, nullptr,nullptr, &t);
if (ret == 0) cout << "连接超时" << endl;
else if (ret < 0) {
cout << "select任务结束,返回错误" << endl;
break;
}
if (FD_ISSET(sock, &fdRead))//判断fdRead集合中是否包含sock,包含了表明发生了改变
{
FD_CLR(sock, &fdRead);
sockaddr_in client = {};
int nAddrLen = sizeof(sockaddr_in);
SOCKET cSock = accept(sock, (sockaddr*)&client, &nAddrLen);//生成新的套接字
if (cSock != SOCKET_ERROR) cout << cSock << "连接成功" << endl;
NewUserJoin user;
user.id = (int)cSock;
for (int i = 0; i < clients.size(); i++)
send(clients[i], (char*)&user, user.dataLength, 0);
clients.push_back(cSock);
}
for (int i = 0; i < clients.size(); i++)
if (FD_ISSET(clients[i], &fdRead)) {//需要判断每一个socket是否发生了改变
int ret = processor(clients[i]);
if (ret == -1) clients.erase(clients.begin() + i);
}
}
客户端改进:
while (true) {
fd_set fdRead;
FD_ZERO(&fdRead);
FD_SET(sock, &fdRead);
timeval t1 = { 5,0 };
int ret = select(sock + 1, &fdRead, nullptr, nullptr, &t1);
if (ret == 0) {
Login login = {};
strcpy_s(login.username, "qwe");
strcpy_s(login.password, "asd");
send(sock, (char*)&login, login.dataLength, 0);
}
else if (ret < 0) {
cout << "select任务结束1" << endl;
break;
}
else {
if (FD_ISSET(sock, &fdRead)) {
FD_CLR(sock, &fdRead);
if (processor(sock) == -1) {
cout << "select任务结束2" << endl;
break;
}
}
}
}