ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
### select 模型 ***** 1.**fd_set** 是文件句柄的集合。            **FD_ZERO** 清空这个集合;       **FD_SET** 往这个集合里面加入一个文件句柄;       **FD_ISSET** 查看某一个文件句柄是否被设置了; 'fd_set') 是一组文件描述符(fd)的集合。由于fd_set类型的长度在不同平台上不同,因此应该用一组标准的宏定义来处理此类变量:     fd_set set;      **FD_ZERO**(&set);        /* 将set清零 */     **FD_SET**(fd, &set);     /* 将fd加入set */      **FD_CLR**(fd, &set);     /* 将fd从set中清除 */      **FD_ISSET**(fd, &set);   /* 如果fd在set中则真 */ ***** ### server代码 ***** **server.cpp** ``` #include <stdio.h> #include <WinSock2.h>//必须放在windows.h前面 #include <Windows.h> #include <stdlib.h> #pragma comment(lib, "ws2_32.lib") fd_set g_fdClientSock; int clientNum = 0; DWORD WINAPI ListenThreadProc(LPARAM lparam) { fd_set fdRead; FD_ZERO(&fdRead); int nRet = 0; char *recvBuffer = (char*)malloc(1024); if (!recvBuffer) { return -1; } memset(recvBuffer, 0, 1024); while (TRUE) { fdRead = g_fdClientSock; timeval vt; vt.tv_sec = 0; vt.tv_usec = 0; nRet = select(0, &fdRead, 0,0,&vt);//会阻塞检查集合中所有socket是否有信号 if (nRet != SOCKET_ERROR) { for (int i=0; i<g_fdClientSock.fd_count; i++) { if (FD_ISSET(g_fdClientSock.fd_array[i], &fdRead)) { memset(recvBuffer, 0, 1024); nRet = recv(g_fdClientSock.fd_array[i], recvBuffer, 1024, 0); if (nRet >0) { //todo: printf("接收到数据:%s", recvBuffer); send(g_fdClientSock.fd_array[i], recvBuffer, strlen(recvBuffer), 0); } else//如果接收失败,则从集合中清除响应socket,并把客户端数量减1 { closesocket(g_fdClientSock.fd_array[i]); clientNum--; FD_CLR(g_fdClientSock.fd_array[i], &g_fdClientSock); } } } } } if (recvBuffer) { free(recvBuffer); recvBuffer=nullptr; } return 0; } void main() { int port = 5099; WSADATA wsaData; if(WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { printf("Failed to load Winsock"); return; } //创建用于监听的套接字 AF_INET:IPV4版本 SOCKET sockSrv = socket(AF_INET, SOCK_STREAM, 0); if (sockSrv == INVALID_SOCKET) { return; } //地址绑定-告诉操作系统是在哪一个地址及端口 SOCKADDR_IN addrSrv; addrSrv.sin_family = AF_INET; addrSrv.sin_port = htons(port); //1024以上的端口号,htons本地转换为网络数据 addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);//电脑上所有的网络ip int retVal = bind(sockSrv, (LPSOCKADDR)&addrSrv, sizeof(SOCKADDR_IN)); if(retVal == SOCKET_ERROR) { printf("绑定bind失败:%d\n", WSAGetLastError()); return; } if(listen(sockSrv,5/*SOMAXCONN*/) ==SOCKET_ERROR) { printf("监听listen失败:%d", WSAGetLastError()); return; } SOCKADDR_IN addrClient;//用于获取连接上来的人的地址信息 int len = sizeof(SOCKADDR); CreateThread(NULL,NULL, (LPTHREAD_START_ROUTINE)ListenThreadProc, NULL, NULL, NULL); while(clientNum < FD_SETSIZE) { //等待客户请求到来 SOCKET clientSock = accept(sockSrv, (SOCKADDR *) &addrClient, &len); if(clientSock == SOCKET_ERROR) { printf("接收Accept失败:%d", WSAGetLastError()); break; } else { printf("接收Accept到客户端IP:[%s]\n", inet_ntoa(addrClient.sin_addr)); } FD_SET(clientSock, &g_fdClientSock);//添加到集合中去 clientNum++;//每次接收到一个人就+1,目前最多接收64个客户 } closesocket(sockSrv); WSACleanup(); system("pause"); } ``` ### client 代码 ***** **client.cpp** ``` // Tcp_client.cpp : 定义控制台应用程序的入口点。 // #include <WinSock2.h> #include <stdio.h> #pragma comment(lib, "ws2_32.lib") void main() { //加载套接字 WSADATA wsaData; char buff[1024]; memset(buff, 0, sizeof(buff)); if(WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { printf("Failed to load Winsock"); return; } SOCKADDR_IN addrSrv; addrSrv.sin_family = AF_INET; addrSrv.sin_port = htons(5099);//http默认端口 addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); //创建套接字 SOCKET sockClient = socket(AF_INET, SOCK_STREAM, 0); if(SOCKET_ERROR == sockClient){ printf("Socket() error:%d", WSAGetLastError()); return; } //向服务器发出连接请求 if(connect(sockClient, (struct sockaddr*)&addrSrv, sizeof(addrSrv)) == INVALID_SOCKET){ printf("Connect failed:%d", WSAGetLastError()); return; } int iRecvLen = 0; //发送数据 char* buffSend = "hello, this is a Client...."; iRecvLen = send(sockClient, buffSend, strlen(buffSend), 0); //接收数据 iRecvLen = recv(sockClient, buff, sizeof(buff), 0); printf("%s\n", buff); //关闭套接字 closesocket(sockClient); WSACleanup(); system("pause"); } ```