AcceptThread()实现接受客户端的连接请求。该函数是一个for循环体。当服务器处于运行状态时,bServerRunning变量为TRUE,不断地等待客户端的连接请求。当服务器处于即将退出状态时,bServerRunning变量为假,该线程退出。
在for循环体中,使用sServer非阻塞套接字不断调用accept()函数。当没有客户端请求接受时,accept()函数立即返回WSAEWOULDBLOCK错误代码。在此情况下,首先调用Sleep()函数使该线程睡眠TIMEFOR_THREAD_SLEEP时间。然后执行continue语句,继续等待客户端的连接请求。
当完成接受客户端请求时,accept()函数返回新建连接的sAccept套接字。sAccept套接字继承sServer套接字的属性。该套接字也将以非阻塞方式工作于在其调用的函数上。
然后,在临界区内使用sAccept套接字和addrClient客户端地址为参数创建一个CClient类的实例。将该实例作为一个节点加入clientlist链表中。
最后调用CClient类的StartRuning()函数,为该客户端创建接收和发送数据线程。关于CClient类将在下面一节中介绍。接受客户端请求线程的程序清单如下。
#define TIMEFOR_THREAD_SLEEP 500 //等待客户端请求线程睡眠时间
/**
* 接受客户端请求
*/
DWORD __stdcall AcceptThread(void* pParam)
{
SOCKET sAccept; //接受客户端连接的套接字
sockaddr_in addrClient; //客户端SOCKET地址
for (;bServerRunning;) //服务器的状态
{
memset(&addrClient, 0, sizeof(sockaddr_in)); //初始化
int lenClient = sizeof(sockaddr_in); //地址长度
sAccept = accept(sServer, (sockaddr*)&addrClient, &lenClient); //接受客户请求
if(INVALID_SOCKET == sAccept )
{
int nErrCode = WSAGetLastError();
if(nErrCode == WSAEWOULDBLOCK) //无法立即完成一个非阻挡性套接字操作
{
Sleep(TIMEFOR_THREAD_SLEEP);
continue; //继续等待
}else {
return 0; //线程退出
}
}
else //接受客户端的请求
{
CClient *pClient = new CClient(sAccept,addrClient); //创建客户端对象
EnterCriticalSection(&csClientList); //进入在临界区
clientlist.push_back(pClient); //加入链表
LeaveCriticalSection(&csClientList); //离开临界区
pClient->StartRuning(); //为接受的客户端建立接收数据和发送数据线程
}
}
return 0;//线程退出
}