SOCKET clientsockarray[FD_SETSIZE - 1];  
char g_buf[1024];BOOL InsertSock(SOCKET* pSock,  SOCKET sock);
DWORD WINAPI WorkerThread(LPVOID lpParam);int main(int argc, char* argv[])
{
WSADATA     wsaData;
SOCKADDR_IN local;
int         iaddrSize = sizeof(SOCKADDR_IN);
DWORD       dwThreadId;
WSAStartup(0x0202, &wsaData);

SOCKET      sListen =  socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
local.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
local.sin_family = AF_INET;
local.sin_port = htons(4096);

bind(sListen, (sockaddr*)&local, sizeof(SOCKADDR_IN));
listen(sListen, 64);
HANDLE hHandle = CreateThread(NULL, 0, WorkerThread, (LPVOID)&sListen, 0, &dwThreadId);  
if (NULL != hHandle)
{
printf("Create Thread Successed\n");
CloseHandle(hHandle);
}
else
{
printf("Create Thread Failed!");
}
getchar();
return 0;
}DWORD WINAPI WorkerThread(LPVOID lpParam)
{
printf("ok\n");
SOCKET listensock = *(SOCKET*)lpParam;
SOCKET clientsock;
int nRet = 0;
fd_set         fdread;
FD_ZERO(&fdread);
u_long lFlag = 1;
nRet =  ioctlsocket(listensock, FIONBIO, &lFlag);
FD_SET(listensock,  &fdread);
for (;;)
{

nRet  = select(0,  &fdread,  NULL,  NULL,  NULL);
if (FD_ISSET(listensock,  &fdread))
{
clientsock = accept(listensock,  NULL,  NULL);

if (!InsertSock(clientsockarray, clientsock))
{
printf("客户端超过了63个,此次连接被拒绝.\n");
closesocket(clientsock);
continue;
}   
}
for (int nIndex = 0;  nIndex < FD_SETSIZE - 1;  nIndex++)
{
if  (FD_ISSET(clientsockarray[nIndex],  &fdread))
{
nRet = recv(clientsockarray[nIndex],  g_buf,  sizeof(g_buf),  0);
if  (nRet  ==  0 || nRet == SOCKET_ERROR)
{
closesocket(clientsockarray[nIndex]);
clientsockarray[nIndex] = INVALID_SOCKET;
continue;      
}
printf("%s\n", g_buf);
}
}
FD_ZERO(&fdread);
FD_SET(listensock, &fdread);
for (nIndex = 0; nIndex < FD_SETSIZE - 1; nIndex++)
{
if (clientsockarray[nIndex] != INVALID_SOCKET)
FD_SET(clientsockarray[nIndex], &fdread);
}
}
}
BOOL InsertSock(SOCKET* pSock,  SOCKET sock)
{
for (int nIndex = 0;  nIndex < FD_SETSIZE - 1; nIndex++)   
{
if(pSock[nIndex]  == INVALID_SOCKET)   
{
pSock[nIndex] = sock;   
break;   
}   
}         
if (nIndex == FD_SETSIZE - 1)   
return FALSE; 
return TRUE;

 }
有几个问题不清楚,希望大家谈谈:
1,在WorkerThread(LPVOID lpParam)线程中是否最多同时有64个客户可以accept成功,不是同时可以接收无限个客户
2,在WorkerThread(LPVOID lpParam)线程中,发现accept连接不成功,可不可以断定同一时刻这个客户是第大于64的客户
3,我发现accept连接不成功,可以在那里再开一个线程吗,一般的服务器怎么处理并发多个客户的?

解决方案 »

  1.   

    另外,好像没有另开一个线程的必要,刚写的代码,通过了,
    // Select.cpp : Defines the entry point for the console application.
    //#include "stdafx.h"
    #include <stdio.h>
    #include <InitSock.h>CInitSock theSock;
    int main(int argc, char* argv[])
    {
    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_set fdSocket;
    FD_ZERO(&fdSocket);
    FD_SET(sListen,&fdSocket); while (true)
    {
    //2) 将fdSocket的一个拷贝fdRead传递给select函数
    //当有事件发生时,select函数移出fdRead集合中没有未决io操作的套接字句柄,返回
    fd_set fdRead=fdSocket;
    int nRet=::select(NULL,&fdRead,NULL,NULL,NULL);
    // printf("hello\n");
    if (nRet>0)
    {
    //3)比较fdSocket和fdRead,确定未决io;
    for (int i=0;i<(int)fdSocket.fd_count;i++)
    {
    // printf("%d",(int)fdSocket.fd_count);
    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)//可读
    {
    szText[nRecv]='\0';
    printf("接收到数据:%s",szText); }
    else         //关闭连接,重启,中断
    {
    ::closesocket(fdSocket.fd_array[i]);
    FD_CLR(fdSocket.fd_array[i],&fdSocket);
    }
    }
    }
    }
    }
    else
    {
    printf("failed select()!\n");
    break;
    }
    }
    return 0;
    }
      

  2.   

    接受几千个客户的最好用IOCPs
      

  3.   

    是有问题:
      u_long lFlag = 1;
    nRet =  ioctlsocket(listensock, FIONBIO, &lFlag);
        用了阻塞的方式,
    而在:
    int nRet=::select(NULL,&fdRead,NULL,NULL,NULL);
    却用了非阻塞的方式
      

  4.   

    用select中,一个线程是多可以有1024个客户连接,那我开100个线程,
    那不最多有10W,
    这样做可以么?
      

  5.   

    lz这种写法,我从来没试过,8知道会是什么样的情况,嘿。一般的做法都是一个线程在listen,accept到新的连接后,开新的线程来处理这个socket,至于如何使用、管理线程,又是另外一个问题
    同时能支持多少个连接?我想这主要是受系统资源限制吧,不知道tcp协议栈软件有没有这种连接数量的限制
      

  6.   

    大体的结构是这样的:
    listen()
    while(1)
    {
        select()
        newsocket=accept();
        _beginthreadex(处理newsocket); //这里怎么管理这些线程,就是你所说的线程池了
        //接着select,等待新的连接
    }
      

  7.   

    1,fd_set 中的 socket数目可以重定义FD_SETSIZE宏来指定,默认是64个。
    2, accept失败时返回值为INVALID_SOCKET;一般可以丢弃这个连接。