一个线程池程序,转发客户端请求到web服务器,程序接受客户端连接,有个clientsocket,然后转发到web服务器有个serversocket,我在serversocket做了个池,思路是程序启动时先建一些,并置状态为未用,当有客户端请求来时建立线程取一个未用serversocket,在打开若干页面时不会断开,但多打开几个却会自动断开,再打网页就打不开了,我监听了池内每个socket的FD_CLOSE事件,然后重新连接,但是还不行,而不用线程池的话就没问题,和用线程池没有本质的区别啊,只是数组保存下,再取出来,哪位哥们有过这种处理经验啊 给指点下 我把关键代码贴出了,能解决马上给分!
threadPool->GetServerSocketPool(); //这里主线程取得socket池部分,不用池就注掉这里
printf("正在接受客户端连接....\n");
bool CThreadPoolManage::GetServerSocketPool()
{
SOCKET ServerSocket=0;
if (serverSocketList.size()==0)
{
HANDLE handle = NULL;
DWORD id = 0;
serverSocketStruct socketStruct;
for(int i=0;i<SOCKETNUM;i++)
{
ServerSocket=ConnectHost();
socketStruct.server=ServerSocket;
socketStruct.reconnected=true;
wsaevent[i]= WSACreateEvent();
int iKeepAlive=-1;
int iOptLen = sizeof(iKeepAlive);
if (getsockopt(ServerSocket, SOL_SOCKET, SO_KEEPALIVE, (char *)&iKeepAlive, &iOptLen) == SOCKET_ERROR)
{
cout << "getsockopt failed. error code = " << WSAGetLastError() << endl;
}
else
{
iKeepAlive = 1;
//这里设置成功的Keep Alive是针对操作系统的所有网络通信
if (setsockopt(ServerSocket, SOL_SOCKET, SO_KEEPALIVE, (char *)&iKeepAlive, iOptLen) == SOCKET_ERROR)
{
cout << "setsockopt failed. error code = " << WSAGetLastError() << endl;
}
else
{
iKeepAlive = -1;
if (getsockopt(ServerSocket, SOL_SOCKET, SO_KEEPALIVE, (char *)&iKeepAlive, &iOptLen) == SOCKET_ERROR)
{
cout << "getsockopt failed. error code = " << WSAGetLastError() << endl;
}
else if (iKeepAlive == 1)
{ // GetQueuedCompletionStatus();
TCP_KEEPALIVE inKeepAlive = {0};
unsigned long ulInLen = sizeof(TCP_KEEPALIVE);
TCP_KEEPALIVE outKeepAlive = {0};
unsigned long ulOutLen = sizeof(TCP_KEEPALIVE);
unsigned long ulBytesReturn=0;
//设置socket的keep alive为10秒,并且发送次数为3次
inKeepAlive.onoff = 1;
inKeepAlive.keepaliveinterval = 5;
inKeepAlive.keepalivetime = 3;
//为选定的SOCKET设置Keep Alive,成功后SOCKET可通过Keep Alive自动检测连接是否断开
if (WSAIoctl(ServerSocket, SIO_KEEPALIVE_VALS,
(LPVOID)&inKeepAlive, ulInLen,
(LPVOID)&outKeepAlive, ulOutLen,
&ulBytesReturn, NULL, NULL) == SOCKET_ERROR)
{
cout << "WSAIoctl failed. error code = " << WSAGetLastError() << endl;
}
}
if (SOCKET_ERROR==WSAEventSelect(ServerSocket,wsaevent[i], FD_CLOSE))
{
i--;
closesocket(ServerSocket);
WSACloseEvent(wsaevent[i]);
continue;
}
socketStruct.used=false;
serverSocketList.push_back(socketStruct);
}
// CreateThread(NULL,NULL,WSAWaitForMultipleEventsThread,(LPVOID)(serverSocketList.size()),0,&id);
//SetEvent(m_HEvent);
}
return true;
}
有任务就
threadPool->AddMission(workThread);从线程池找出空闲线程开始
往下执行 这个是线程函数
int WorkerThread::PortTransfer()
{
SOCKET ServerSock;
//先连接到目标计算机的服务
// ServerSock =threadPool->GetServerSocket(this->socketIndex);去socket池socket
ServerSock=threadPool->ConnectHost();这个没有问题
if(ServerSock <= 0)
{
closesocket(this->ClientSocket);
return 0;
}
SOCKINFO socks;
socks.ClientSock = this->ClientSocket;//客户的套接字
socks.ServerSock = ServerSock;//目标计算机服务的套接字
//进入纯数据转发状态
return TransmitData((LPVOID)&socks);
}DWORD WINAPI WorkerThread::TransmitData(LPVOID lParam)//在两个SOCKET中进行数据转发
{
SOCKINFO socks = *((SOCKINFO*)lParam);
SOCKET ClientSock = socks.ClientSock;
SOCKET ServerSock = socks.ServerSock;
char RecvBuf[MAXBUFSIZE] = {0};
fd_set Fd_Read;
int ret, nRecv; while(1)
{ ::EnterCriticalSection(§ion);
FD_ZERO(&Fd_Read);
FD_SET(ClientSock, &Fd_Read);
FD_SET(ServerSock, &Fd_Read);
ret = select(FD_SETSIZE, &Fd_Read, NULL, NULL, NULL);
if(ret <= 0)
goto error;
if(FD_ISSET(ClientSock, &Fd_Read))
{
nRecv = recv(ClientSock, RecvBuf, sizeof(RecvBuf), 0);
if(nRecv <= 0)
goto error;
ret = DataSend(ServerSock, RecvBuf, nRecv);
if(ret == 0 || ret != nRecv)
goto error;
}
if(FD_ISSET(ServerSock, &Fd_Read))
{
nRecv = recv(ServerSock, RecvBuf, sizeof(RecvBuf), 0);
int a=WSAGetLastError();
if(nRecv <= 0)
goto error;
ret = DataSend(ClientSock, RecvBuf, nRecv);
if(ret == 0 || ret != nRecv)
goto error;
}
::LeaveCriticalSection(§ion);
} error:
::EnterCriticalSection(&errorsection);
closesocket(ClientSock);
if (NULL!=threadPool)
{
// threadPool->serverSocketList[socketIndex].used=false; 这里是socket池部分,如果出错就置标志位 重新连接
// threadPool->serverSocketList[socketIndex].reconnected=false;
threadPool->socketList.push_back(ServerSock);不用socket池的话,收集serverscoket定时销毁重建
}
::LeaveCriticalSection(&errorsection);
return 0;
}