//////////////////////////////////////////////////////
// select.cpp文件
//select的优点是程序能够在单个线程内同时处理多个套接字连接,但是增加
//到fd_set结构的套接字是有限制的。winsock2.h定义为64,在包含winsock2.h
//之前重新定义它是可以的,但是最大不能超过1024,并且此值太大,影响服
//务器性能,因为select返回之前会检查这些集合中的套接字,并移除没有未
//决I/O操作的套接字。
//s为套接字
//FD_ZERO(*set)初始化set为空集合
//FD_CLR(s,*set)从set移除s
//FD_ISSET(s,*set)检查s是不是set的成员,如果是返回true
//FD_SET(s,*set)增加套接字到集合
#include "../common/initsock.h"
#include <stdio.h>
CInitSock theSock;//初始化Winsock库
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);
// select模型处理过程
// 1)初始化一个套节字集合fdSocket,添加监听套节字句柄到这个集合
fd_setfdSocket;// 所有可用套节字集合
FD_ZERO(&fdSocket);
FD_SET(sListen, &fdSocket);
while(TRUE)
{
//2)将fdSocket集合的一个拷贝fdRead传递给select函数,
//当有事件发生时,select函数移除fdRead集合中没有未决I/O操作的套节字句柄,然后返回。
fd_set fdRead = fdSocket;
int nRet = ::select(0,&fdRead, NULL, NULL, NULL);
if(nRet >0)
{
//3)通过将原来fdSocket集合与select处理过的fdRead集合比较,
//确定都有哪些套节字有未决I/O,并进一步处理这些I/O。
for(int i=0;i<(int)fdSocket.fd_count; i++)
{
if(FD_ISSET(fdSocket.fd_array[i],&fdRead))
{
if(fdSocket.fd_array[i]== sListen)//(1)监听套节字接收到新连接
{
if(fdSocket.fd_count< FD_SETSIZE)
{
sockaddr_inaddrRemote;
intnAddrLen = sizeof(addrRemote);
SOCKETsNew = ::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
{
charszText[256];
intnRecv = ::recv(fdSocket.fd_array[i], szText, strlen(szText),0);
if(nRecv>0)//(2)可读
{
szText[nRecv]= '\0';
printf("接收到数据:%s\n", szText);
}
else//(3)连接关闭、重启或者中断
{
::closesocket(fdSocket.fd_array[i]);
FD_CLR(fdSocket.fd_array[i],&fdSocket);
}
}
}
}
}
else
{
printf("Failed select() \n");
break;
}
}
return 0;