首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > VC/MFC >

为何小弟我的SOCKET线程只能接受一个连接

2014-06-19 
为何我的SOCKET线程只能接受一个连接?用了别人的一个IO重叠写的网络服务端,但是发现只能接受一个客户端。没

为何我的SOCKET线程只能接受一个连接?
用了别人的一个IO重叠写的网络服务端,但是发现只能接受一个客户端。没有找到问题出在那里。

int CServerSocket::StartListening(const UINT& port)
{
WSADATA wsaData;
int nRet;
nRet=WSAStartup(MAKEWORD(2,2),&wsaData);  
if(nRet!=0)
{
AfxMessageBox("Load winsock2 failed");
WSACleanup();
return -1;
}
sockListen = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); //创建服务套接字(TCP)
SOCKADDR_IN ServerAddr; //分配端口及协议族并绑定
ServerAddr.sin_family=AF_INET;  
ServerAddr.sin_addr.S_un.S_addr =htonl(INADDR_ANY);  
ServerAddr.sin_port=htons(port);
nRet=bind(sockListen,(LPSOCKADDR)&ServerAddr,sizeof(ServerAddr)); // 绑定套接字
if(nRet==SOCKET_ERROR)
{
AfxMessageBox("Bind Socket Fail!");
closesocket(sockListen);
return -1;
}
nRet=listen(sockListen,1);  
if(nRet==SOCKET_ERROR)  
{
AfxMessageBox("Listening Fail!");
return -1;
}
pServerListenThread = AfxBeginThread(_ServerListenThread, this); //启动线程
pWaitForCompletionThread = AfxBeginThread( _WaitForCompletionThread,this,THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED,NULL); 
return 0;
}


UINT _ServerListenThread(LPVOID lParam)
{
TRACE("服务器端监听中.....\n");

CServerSocket* pServer = (CServerSocket*)lParam;

SOCKADDR_IN ClientAddr;  
int addr_length=sizeof(ClientAddr);

while(TRUE)
{
SOCKET sockTemp = accept(sockListen,(SOCKADDR*)&ClientAddr,&addr_length); 

if(sockTemp == INVALID_SOCKET)  
{
AfxMessageBox("Accept Connection failed!");
continue;
}

nSockIndex = pServer->GetEmptySocket(); // 获得一个空闲的SOCKET索引号
sockArray[nSockIndex] = sockTemp; // 将这个SOCKET句柄存入到数组中
nSockTotal++; // SOCKET总数加一
bNewSocket = TRUE; // 标志投递一个新的WSARecv请求

if(nSockTotal >= 1) // SOCKET数量不为空时激活处理线程
pWaitForCompletionThread->ResumeThread();
}

return 0;
}


UINT _WaitForCompletionThread(LPVOID lParam)
{
EventArray[0] = WSACreateEvent();  
DWORD dwRecvBytes = 0, Flags = 0;

while(TRUE)
{
if(bNewSocket)  
{
bNewSocket = FALSE;
Flags = 0;
ZeroMemory(&AcceptOverlapped[nSockIndex],sizeof(WSAOVERLAPPED));
char buffer[DATA_BUFSIZE];
ZeroMemory(buffer,DATA_BUFSIZE);

DataBuf[nSockIndex].len = DATA_BUFSIZE;
DataBuf[nSockIndex].buf = buffer;

if(WSARecv(
sockArray[nSockIndex],
&DataBuf[nSockIndex],
1,
&dwRecvBytes,
&Flags,
&AcceptOverlapped[nSockIndex],
_CompletionRoutine) == SOCKET_ERROR)
{
if(WSAGetLastError() != WSA_IO_PENDING)
{
ReleaseSocket(nSockIndex);
continue;
}
}
}

DWORD dwIndex = WSAWaitForMultipleEvents(1,EventArray,FALSE,WSA_INFINITE,TRUE);

if(dwIndex == WAIT_IO_COMPLETION)
{
if(nCurSockIndex != NULLSOCKET)  
{
Flags = 0;
ZeroMemory(&AcceptOverlapped[nCurSockIndex],sizeof(WSAOVERLAPPED));
char buffer[DATA_BUFSIZE];
ZeroMemory(buffer,DATA_BUFSIZE);

DataBuf[nCurSockIndex].len = DATA_BUFSIZE;
DataBuf[nCurSockIndex].buf = buffer;

if(WSARecv(
sockArray[nCurSockIndex],
&DataBuf[nCurSockIndex],


1,
&dwRecvBytes,
&Flags,
&AcceptOverlapped[nCurSockIndex],
_CompletionRoutine // 注意这个回调函数
) == SOCKET_ERROR)
{
if(WSAGetLastError() != WSA_IO_PENDING) // 出现错误,关闭SOCKET
{
ReleaseSocket(nCurSockIndex);
continue;
}
}
}
continue;
}
else  
{
if(dwIndex == WAIT_TIMEOUT)  
continue;
else  

AfxMessageBox("_WaitForCompletionThread 发生异常,线程将退出!");
break;
}
}
}
return 0;
}


void CALLBACK CompletionRoutine(DWORD Error,
DWORD BytesTransfered,
LPWSAOVERLAPPED Overlapped,
DWORD inFlags)
{
TRACE("回调PolicyCompletionRoutine......");

nCurSockIndex = GetCurrentSocketIndex(Overlapped);  
if(Error != 0 || BytesTransfered == 0)  
{
ReleaseSocket(nCurSockIndex);
return;
}
CString strtemp="";
strtemp=DataBuf[nCurSockIndex].buf;

if(strtemp.GetLength()<10 )
{
g_MyLog.LogString("recvdatabuf=%s",strtemp);
return;
}
OutputDebugString(strtemp);
return;
}


只是该服务端监听了两个端口,用了相似的函数和方法,另一个端口可以连接多个客户端。只是上一个连了上来之后回了消息就断开。

[解决办法]
代码排版太烂了,要用插入源代码的方式发贴。

你的代码问题太多,比如多线程没有保护全局变量,特别严重的问题就是,异步IO需要用临时缓存:
char buffer[DATA_BUFSIZE];

先不要急于解决你所谓的问题,把已知的这些问题解决了再说吧,欠的迟早要还的,说不定你的问题就是由这些看似不想干的问题引起的。
[解决办法]
你用的是异步IO,WSARecv之后,马上就返回了,然后你就做其它事了,比如再对另外一个套接字做WSARecv,等数据真正到来的时候,系统会把数据拷贝到DataBuf[nCurSockIndex].buf里面,此时你的buffer在哪里呢?还有效吗?

热点排行