#include <WinSock2.h>
#include <stdio.h>
#define PORT 6000
#pragma comment (lib, "Ws2_32.lib")
fd_set g_fdClientSock; //file discriotin set集合
int clientNum = 0;
BOOL WinSockInit()
{
WSADATA data = { 0 };
if (WSAStartup(MAKEWORD(2, 2), &data))
return FALSE;
if (LOBYTE(data.wVersion) != 2 || HIBYTE(data.wVersion) != 2)
{
WSACleanup();
return FALSE;
}
return TRUE;
}
DWORD WINAPI ListenThreadProc(LPARAM lparam)
{
fd_set fdRead;
FD_ZERO(&fdRead);
int nRet = 0;
char* recvBuffer = (char*)malloc(sizeof(char)* 1024);
if (NULL == recvBuffer)
{
return -1;
}
memset(recvBuffer, 0, sizeof(char)* 1024);
while (true)
{
fdRead = g_fdClientSock;
timeval tv;
tv.tv_sec = 1;
tv.tv_usec = 0;
//select操作会阻塞的检查整个FD_SET数组里面的所有soket是否有信号来了
//解决了标准TCP n个客户就要n+1个线程的问题
//线程时间片没有充分利用
nRet = select(0, &fdRead, NULL, NULL, &tv); //sleep将线程休眠操作
if (nRet != SOCKET_ERROR)
{
//找到数组内哪个sokect有信号
for (int i = 0; i < g_fdClientSock.fd_count; i++)
{
//遍历有哪些sokect有数据信号到达
if (FD_ISSET(g_fdClientSock.fd_array[i], &fdRead))
{
//与客户通信
memset(recvBuffer, 0, sizeof(char)* 1024);
nRet=(recv(g_fdClientSock.fd_array[i], recvBuffer, 1024, 0));
if (nRet == SOCKET_ERROR)
{
closesocket(g_fdClientSock.fd_array[i]);
clientNum--;
FD_CLR(g_fdClientSock.fd_array[i], &g_fdClientSock);
}
else if (nRet==0)
{
closesocket(g_fdClientSock.fd_array[i]);
clientNum--;
FD_CLR(g_fdClientSock.fd_array[i], &g_fdClientSock);
}
else
{
//todo:后续处理
printf("Recv msg:%s\n", recvBuffer);
send(g_fdClientSock.fd_array[i], recvBuffer, strlen(recvBuffer), 0);
}
}
}
}
}
if (recvBuffer != NULL)
free(recvBuffer);
return 0;
}
int main()
{
WinSockInit();
SOCKET ListenSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl(INADDR_ANY);
server.sin_port = htons(PORT);
int ret = bind(ListenSock, (sockaddr*)&server, sizeof(server));
ret = listen(ListenSock, 4);
sockaddr_in clientAddr;
int nameLen = sizeof(clientAddr);
//先把服务器创建起来
CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)ListenThreadProc, NULL, NULL, NULL);
//主线程里面开始进行Accept操作
while (clientNum < FD_SETSIZE) //FD_SETSIZE=64
{
//当有一个客户端进行连接时,主线程的Accept会进行返回
SOCKET clientSock = accept(ListenSock, (sockaddr*)&clientAddr, &nameLen);
FD_SET(clientSock, &g_fdClientSock);
clientNum++;
}
closesocket(ListenSock);
WSACleanup();
return 0;
}
【Windows网络编程】Select网络模型
最新推荐文章于 2024-08-13 19:34:42 发布