winsocket c++ IO复用 之Select

Select对于一个I/O端口,两次调用,两次返回,比阻塞I/O并没有什么优越性,关键是能实现同时对多个IO端口进行监听。





#include <winsock.h>
#include <stdio.h>
#define PORT       22000
#define MSGSIZE    1024
#pragma comment(lib, "ws2_32.lib")
int    g_iTotalConn = 0;
SOCKET g_CliSocketArr[FD_SETSIZE];
DWORD WINAPI WorkerThread(LPVOID lpParameter);
int main()
{
WSADATA     wsaData;
SOCKET      sListen, sClient;
SOCKADDR_IN local, client;
int         iaddrSize = sizeof(SOCKADDR_IN);
DWORD       dwThreadId;
// Initialize Windows socket library
WSAStartup(0x0202, &wsaData);
// Create listening socket
sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
// Bind
local.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
local.sin_family = AF_INET;
local.sin_port = htons(PORT);
bind(sListen, (struct sockaddr *)&local, sizeof(SOCKADDR_IN));
// Listen
listen(sListen, 3);
// Create worker thread
CreateThread(NULL, 0, WorkerThread, NULL, 0, &dwThreadId); 
while (TRUE)
{
// Accept a connection
sClient = accept(sListen, (struct sockaddr *)&client, &iaddrSize);
printf("Accepted client:%s:%d\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port));
// Add socket to g_CliSocketArr
g_CliSocketArr[g_iTotalConn++] = sClient;
}


return 0;
}
DWORD WINAPI WorkerThread(LPVOID lpParam)
{
int            i;
fd_set         fdread;
int            ret;
struct timeval tv = {1, 0};
char           szMessage[MSGSIZE];


while (TRUE)
{
FD_ZERO(&fdread);
for (i = 0; i < g_iTotalConn; i++)
{
FD_SET(g_CliSocketArr[i], &fdread);
}
// We only care read event
ret = select(0, &fdread, NULL, NULL, &tv);
if (ret == 0)
{
// Time expired
continue;
}
for (i = 0; i < g_iTotalConn; i++)
{
if (FD_ISSET(g_CliSocketArr[i], &fdread))
{
// A read event happened on g_CliSocketArr
ret = recv(g_CliSocketArr[i], szMessage, MSGSIZE, 0);
if (ret == 0 || (ret == SOCKET_ERROR && WSAGetLastError() == WSAECONNRESET))
{
// Client socket closed
printf("Client socket %d closed.\n", g_CliSocketArr);
closesocket(g_CliSocketArr[i]);
if (i < g_iTotalConn - 1)
{           
g_CliSocketArr[i--] = g_CliSocketArr[--g_iTotalConn];
}
}
else
{
// We received a message from client
szMessage[ret] = '\0';
send(g_CliSocketArr[i], szMessage, strlen(szMessage), 0);
}
}
}
}


return 0;
}


需要关注的是Select模型 

 FD_ZERO(&set);//将你的套节字集合清空 
 FD_SET(s,   &set);//加入你感兴趣的套节字到集合,这里是一个读数据的套节字s 
 select(0,&set,NULL,NULL,NULL);//检查套节字是否可读, 
                                                      //很多情况下就是是否有数据(注意,只是说很多情况) 
                                                      //这里select是否出错没有写 
    if(FD_ISSET(s,   &set)   //检查s是否在这个集合里面, 
    {                                           //select将更新这个集合,把其中不可读的套节字去掉 
                                                //只保留符合条件的套节字在这个集合里面 
                                
            recv(s,...); 
    
    } 




猜你喜欢

转载自blog.csdn.net/myt0929/article/details/52353319
今日推荐