IOCP同一个链接上多次Send和Recv的问题
本帖最后由 woshiqinxue 于 2013-08-15 22:49:13 编辑 我有一个Serve和Client,但是在测试的时候Client只有第一次Send可以在Serve上的处理线程上接收到。请帮忙看看;还有我想问问下面代码这样的方式是不是可以实现1000个连接的并发处理,处理的效率怎么样?
下面是代码:
Serve:
int _tmain(int argc, _TCHAR* argv[])
{
InitWinsock();
HANDLE CompletionPort =CreateIoCompletionPort(INVALID_HANDLE_VALUE,
NULL, 0, 0);
//根据系统的CPU来创建工作者线程
SYSTEM_INFO SystemInfo;
GetSystemInfo(&SystemInfo);
//线程数目=系统进程数目的两倍.
for(int i=0; i!=SystemInfo.dwNumberOfProcessors * 2; ++i)
{
HANDLE hProcessIO = CreateThread(NULL, 0, ProcessIO,
CompletionPort, 0, NULL);
if(hProcessIO)
{
CloseHandle(hProcessIO);
}
}
//创建侦听SOCKET
SOCKET sListen = BindServerOverlapped(PORT);
SOCKET sClient;
LPPER_HANDLE_DATA PerHandleData;
LPPER_IO_OPERATION_DATA PerIoData;
while(TRUE)
{
//sClient = WSAAccept(sListen, NULL, NULL, NULL, 0);
sClient = accept(sListen, 0, 0);
cout << "Socket " << sClient << "连接进来\n"<< endl;
PerHandleData = new PER_HANDLE_DATA();
PerHandleData->Socket = sClient;
CreateIoCompletionPort((HANDLE)sClient, CompletionPort,
(DWORD)PerHandleData, 0);
// 建立一个Overlapped,并使用这个Overlapped结构对socket投递操作
PerIoData = new PER_IO_OPERATION_DATA();
ZeroMemory(PerIoData, sizeof(PER_IO_OPERATION_DATA));
PerIoData->DataBuf.buf = PerIoData->Buffer;
PerIoData->DataBuf.len = DATA_BUFSIZE;
DWORD Flags = 0;
DWORD dwRecv = 0;
WSARecv(sClient, &PerIoData->DataBuf, 1, &dwRecv,
&Flags, &PerIoData->Overlapped, NULL);
}
DWORD dwByteTrans;
//将一个已经完成的IO通知添加到IO完成端口的队列中.
//提供了与线程池中的所有线程通信的方式.
PostQueuedCompletionStatus(CompletionPort,
dwByteTrans, 0, 0); //IO操作完成时接收的字节数.
closesocket(sListen);
return 0;
}
DWORD WINAPI ProcessIO(LPVOID lpParam)
{
HANDLE CompletionPort = (HANDLE)lpParam;
DWORD BytesTransferred;
LPPER_HANDLE_DATA PerHandleData;
LPPER_IO_OPERATION_DATA PerIoData;
while(true)
{
if(0 == ::GetQueuedCompletionStatus(CompletionPort,
&BytesTransferred, (LPDWORD)&PerHandleData,(LPOVERLAPPED*)&PerIoData, INFINITE))
{
DWORD er = GetLastError();
if( (GetLastError() ==WAIT_TIMEOUT) ||
(GetLastError() == ERROR_NETNAME_DELETED) )
{
cout << "closingsocket" << PerHandleData->Socket \
<< "\n" << endl;
closesocket(PerHandleData->Socket);
if (PerIoData != NULL)
{
delete PerIoData;
PerIoData = NULL;
}
if (PerHandleData != NULL)
{
delete PerHandleData;
PerHandleData = NULL;
}
continue;
}
else
{
cout << "GetQueuedCompletionStatus failed!\n" << endl;
}
return 0;
}
// 说明客户端已经退出
if(BytesTransferred == 0)
{
cout << "closing socket" <<PerHandleData->Socket << "\n" << endl;
closesocket(PerHandleData->Socket);
if (PerIoData != NULL)
{
delete PerIoData;
PerIoData = NULL;
}
if (PerHandleData != NULL)
{
delete PerHandleData;
PerHandleData = NULL;
}
continue;
}
// 取得数据并处理
memcpy((void*)&dsr, PerIoData->Buffer, strlen(PerIoData->Buffer));
cout << PerHandleData->Socket<< "发送过来的消息:"<< \
PerIoData->Buffer <<"\n" << endl;
}
return 0;
}
iocp socket
int _tmain(int argc, _TCHAR* argv[])
{
InitializeCriticalSection(&g_cs);
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD( 2, 2);
err = WSAStartup( wVersionRequested,&wsaData );//WSAStartup()加载套接字库
if ( err != 0 ) {
return -1;
}
if ( LOBYTE( wsaData.wVersion ) != 2 ||
HIBYTE( wsaData.wVersion ) != 2 ){
WSACleanup( );
return -1;
}
HANDLE hThread = CreateThread(NULL, 0, ProcessThread, 0, 0, NULL);
if(hThread==NULL)
{
WSACleanup();
return 0;
}
WaitForSingleObject(hThread, INFINITE);
WSACleanup();
return 0;
}
DWORD WINAPI ProcessThread(LPVOID lpParam)
{
int nCnt = 0;
char sendBuf[MAX_SENDBUF];
char recvBuf[MAX_RECVBUF];
SOCKET sockClient = socket(AF_INET,SOCK_STREAM,0);
if(sockClient == INVALID_SOCKET)
{
cout<<"socket 失败"<<endl;
return -1;
}
nCnt++;
SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(5050);//和服务器端的端口号保持一致
connect(sockClient, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));
while(nCnt < MAXCNT)
{
nCnt++;
memset(sendBuf, 0, sizeof(char)*MAX_SENDBUF);
sprintf(sendBuf, "This is Thread %d:", nCnt++);
send(sockClient, sendBuf, sizeof(sendBuf)+1, 0);
sleep(1000);
}
closesocket(sockClient);
return 0;
}