select模式的思想
创建FD_SET fd_all,并初始化FD_ZERO(&fd_all);
Step1 初始时:
Step2 加入一个套接字之后,比如FD_SET(sServer,&fd_all);
Step3 调用select函数之后,有两种情况
上述的select假设是在非阻塞的情况下。由图示可以看出, select对FD_SET的结构进行了动态改变,没有变化的会置为0,有变化的会保持为1,这就是select的思想。
//
保持FD_SET的状态
假设有1,2,3,4四个标号的套接字加入FD_SET
//伪码FD_SET(1,&fd_all);FD_SET(2,&fd_all);FD_SET(3,&fd_all);FD_SET(4,&fd_all);for(;;){ ... select(0,&fd_all,0,NULL,NULL); ...}
在进行选择之后,有些套接字可能暂时没有数据收发就被select函数过滤掉了,所以要保持套接字的状态,模式如下:
//保持套接字状态的方法示例 while(true) { fd_read=fd_all; fd_write=fd_all; select(0,&fd_read,0,NULL,NULL);//①阻塞; for(UINT i=0;i
版本一(有点问题,需要修正):
/**************************************************************************************************************
2018/10/9号进行修正:
原因:
1. 在select轮询时,如果没有连接返回-1
2. 在while循环时,需要Sleep(100),不然CPU空转太厉害导致CPU使用率上升!/**************************************************************************************************************
#include#include #include #pragma comment(lib,"ws2_32.lib")#define PORT 8000#define MSGSIZE 255#define SRV_IP "127.0.0.1"int g_nSockConn = 0; //请求连接的数目struct ClientInfo{ SOCKET sockClient; //客户端套接字 SOCKADDR_IN addrClient; //客户端地址};ClientInfo g_Client[FD_SETSIZE]; //客户端套接字集合;DWORD WINAPI WorkThread(LPVOID lpParameter);int main(int argc, char *argv[]){ WSADATA wsd; WSAStartup(MAKEWORD(2, 2), &wsd); SOCKET sockListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);//创建套接字 SOCKADDR_IN addrSrv; addrSrv.sin_addr.S_un.S_addr = inet_addr(SRV_IP); addrSrv.sin_family = AF_INET; addrSrv.sin_port = htons(PORT); bind(sockListen, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));//绑定 listen(sockListen, 64);//监听 DWORD dwThreadIDRecv = 0; DWORD dwThreadIDWrite = 0; HANDLE hand = CreateThread(NULL, 0, WorkThread, NULL, 0, &dwThreadIDRecv);//工作线程 if (hand == NULL) { std::cout <<"创建线程失败!"<
版本二(正常运行):
#include#include "initSocket.h"CInitSock theSock; int main(){ USHORT nPort = 4567; SOCKET sListen = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); sockaddr_in sin; sin.sin_family = AF_INET; sin.sin_port = htons(nPort); sin.sin_addr.S_un.S_addr = INADDR_ANY; if (::bind(sListen, (sockaddr*)&sin, sizeof(sin)) == SOCKET_ERROR) { printf(" Failed bind() \n"); return -1; } ::listen(sListen, 5); fd_set fdSocket; FD_ZERO(&fdSocket); FD_SET(sListen, &fdSocket); while (TRUE) { fd_set fdRead = fdSocket; int nRet = ::select(0, &fdRead, NULL, NULL, NULL); if (nRet > 0) { for (int i = 0; i < (int)fdSocket.fd_count; i++) { if (FD_ISSET(fdSocket.fd_array[i], &fdRead)) { if (fdSocket.fd_array[i] == sListen) { if (fdSocket.fd_count < FD_SETSIZE) { sockaddr_in addrRemote; int nAddrLen = sizeof(addrRemote); SOCKET sNew = ::accept(sListen, (SOCKADDR*)&addrRemote, &nAddrLen); FD_SET(sNew, &fdSocket); printf("接收到连接(%s)\n", ::inet_ntoa(addrRemote.sin_addr)); } else { printf(" Too much connections! \n"); continue; } } else { char szText[256]; int nRecv = ::recv(fdSocket.fd_array[i], szText, strlen(szText), 0); if (nRecv > 0) // (2)可读 { szText[nRecv] = '\0'; printf("接收到数据:%s \n", szText); } else { printf("连接断开...!"); ::closesocket(fdSocket.fd_array[i]); FD_CLR(fdSocket.fd_array[i], &fdSocket); } } } } } else { printf(" Failed select() \n"); break; } } return 0;}