IOCP(完成端口)的问题,客户端连接到16个就断,不知道为什么,已经晕了,跪求牛人

wokagoka 2011-10-18 10:23:18
服务端代码:

#pragma warning(disable:4996)
#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1

#include "stdafx.h"
#include <winsock2.h>
#include <windows.h>
#include <process.h>
#include <iostream>
using namespace std;

#pragma comment(lib,"ws2_32.lib")

#define MAX_BUFFER_SIZE 2048

typedef enum
{
IO_NONE,
IO_READ,
IO_WRITE
}IO_OPERATION_INFO, *LPIO_OPERATION_INFO;

typedef struct
{
SOCKET CurrentSocket;
} PER_HANDLE_DATA, *LPPER_HANDLE_DATA;

typedef struct
{
WSAOVERLAPPED Overlapped;
CHAR Buffer[MAX_BUFFER_SIZE];
WSABUF WSABuffer;
//SOCKET CurrentSocket;
SOCKADDR_IN CurrentRemoteAddr;
IO_OPERATION_INFO OperationType;
} PER_IO_DATA, *LPPER_IO_DATA;

unsigned __stdcall ServerWorkerThread(LPVOID CompletionPortID)
{
HANDLE hCompletionPort = (HANDLE)CompletionPortID;


while(TRUE)
{
DWORD dwByteTransferred = 0;
DWORD dwFlag = 0;
LPPER_IO_DATA lpData = NULL;
LPWSAOVERLAPPED lpOverlapped = NULL;
LPPER_HANDLE_DATA lpHandleData = NULL;

cout << "hCompletionPort:" << hCompletionPort << endl;

BOOL state = GetQueuedCompletionStatus(hCompletionPort,
&dwByteTransferred,
(PULONG_PTR)&lpHandleData,
&lpOverlapped,
INFINITE);
if(!state)
{
cout << "GetQueuedCompletionStatus操作失败!"
<< WSAGetLastError() << endl;
continue;
}

lpData = CONTAINING_RECORD(lpOverlapped, PER_IO_DATA, Overlapped);

if(dwByteTransferred == 0)
{
cout << "发过来的数据长度为0" << endl;

closesocket(lpHandleData->CurrentSocket);
delete lpData;
lpData = NULL;
delete lpOverlapped;
lpOverlapped = NULL;
continue;
}

switch (lpData->OperationType)
{
case IO_READ:
{
char *ip = inet_ntoa(lpData->CurrentRemoteAddr.sin_addr);
u_short port = ntohs(lpData->CurrentRemoteAddr.sin_port);
cout << "IO_READ_客户连接地址:" << ip << "。端口:" << port;
cout << "。已接收到数据:" << lpData->Buffer << endl;

lpData->OperationType = IO_WRITE;
memset(
&(lpData->Overlapped), 0,
sizeof(lpData->Overlapped));
/*cout << "Socket:" << &lpData->CurrentSocket << endl;
cout << "WSABuffer:" << &lpData->WSABuffer << endl;
cout << "dwByteTransferred:" << dwByteTransferred << endl;
cout << "dwFlag:" << dwFlag << endl;
cout << "lpData->Overlapped:" << &lpData->Overlapped << endl;
cout << endl;*/


int ret = WSASend(
lpHandleData->CurrentSocket,
&(lpData->WSABuffer), 1,
&dwByteTransferred, dwFlag,
&(lpData->Overlapped), NULL);


if(ret == SOCKET_ERROR)
{
if(WSA_IO_PENDING != WSAGetLastError())
{
/*closesocket(lpData->CurrentSocket);
if(lpData != NULL)
{
delete lpData;
lpData = NULL;
}*/
cout << "is not WSA_IO_PENDING!" << endl;
continue;
}
}
}
break;
case IO_WRITE:
{
cout << "IO_WRITE" << endl;
cout << endl;

lpData->OperationType = IO_READ;
dwFlag = 0;
memset(&lpData->Overlapped, 0, sizeof(lpData->Overlapped));
memset(lpData->Buffer, 0, sizeof(lpData->Buffer));
lpData->WSABuffer.buf = lpData->Buffer;
dwByteTransferred = lpData->WSABuffer.len = MAX_BUFFER_SIZE;

int ret = WSARecv(lpHandleData->CurrentSocket,
&(lpData->WSABuffer), 1,
&dwByteTransferred,
&dwFlag,
&(lpData->Overlapped), NULL);

if(ret == SOCKET_ERROR)
{
if(WSA_IO_PENDING != WSAGetLastError())
{
/*closesocket(lpData->CurrentSocket);
delete lpData;
lpData = NULL;*/
continue;;
}
}

}
break;
default:
break;
}


}

return 0;
}


int _tmain(int argc, _TCHAR* argv[])
{
WSADATA wsaData;
if(0 != WSAStartup(MAKEWORD(2, 2), &wsaData))
{
printf("WSAStartup failed with error code: %d/n", GetLastError());
return EXIT_FAILURE;
}
if(2 != HIBYTE(wsaData.wVersion) || 2 != LOBYTE(wsaData.wVersion))
{
WSACleanup();
return EXIT_FAILURE;
}

HANDLE hCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);


SYSTEM_INFO SysInfo;
GetSystemInfo(&SysInfo);

int ThreadCount = SysInfo.dwNumberOfProcessors;
HANDLE hThreadHandles[2];
for (int i = 0; i < ThreadCount; i++)
{
//DWORD dwThreadId;
//hThreadHandles[i] = CreateThread(NULL, 0, ServerWorkerThread, (LPVOID)hCompletionPort, 0, &dwThreadId);
hThreadHandles[i] = (HANDLE)_beginthreadex(NULL, 0, ServerWorkerThread, (LPVOID)hCompletionPort, 0, NULL);
}

SOCKET mainSocket = WSASocket(
AF_INET, SOCK_STREAM,
IPPROTO_TCP, NULL, 0,
WSA_FLAG_OVERLAPPED);

sockaddr_in server;
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl(INADDR_ANY);
server.sin_port = htons(5600);
bind(mainSocket, (PSOCKADDR)&server, sizeof(server));

listen(mainSocket, 5);

while (TRUE)
{
SOCKADDR_IN remote;
memset(&remote, 0, sizeof(SOCKADDR_IN));
int len = sizeof(SOCKADDR_IN);

SOCKET aptSocket = WSAAccept(
mainSocket,
(LPSOCKADDR)&remote,
&len, NULL, NULL);

if(aptSocket == INVALID_SOCKET)
{
continue;
}

LPPER_IO_DATA lpData = new PER_IO_DATA;
//lpData->CurrentSocket = aptSocket;

LPPER_HANDLE_DATA lpHandleData = new PER_HANDLE_DATA;

lpHandleData->CurrentSocket = aptSocket;

lpData->CurrentRemoteAddr = remote;
memset(&lpData->Overlapped, 0, sizeof(WSAOVERLAPPED));
memset(&lpData->Buffer, 0, MAX_BUFFER_SIZE);
lpData->WSABuffer.buf = lpData->Buffer;
lpData->WSABuffer.len = MAX_BUFFER_SIZE;
lpData->OperationType = IO_READ;

CreateIoCompletionPort(
(HANDLE)aptSocket,
hCompletionPort,
(ULONG_PTR)lpHandleData, 0);

DWORD dwRecvNumBytes=lpData->WSABuffer.len, dwFlags=0;

int ret = WSARecv(lpHandleData->CurrentSocket,
&(lpData->WSABuffer), 1,
&dwRecvNumBytes, &dwFlags,
&(lpData->Overlapped),
NULL);

if(ret == SOCKET_ERROR)
{
if(WSA_IO_PENDING != WSAGetLastError())
{
closesocket(aptSocket);
delete lpData;
lpData= NULL;
}
}
}

PostQueuedCompletionStatus(hCompletionPort, 0, NULL, NULL);
WaitForMultipleObjects(ThreadCount, hThreadHandles, TRUE, INFINITE);
for (int i=0; i<ThreadCount; i++)
{
CloseHandle(hThreadHandles[i]);
}
CloseHandle(hCompletionPort);
closesocket(mainSocket);
WSACleanup();

return 0;
}


客户端代码:

// IOCPClient.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <WinSock2.h>
#include <windows.h>
#include <iostream>
#pragma comment(lib,"ws2_32.lib")
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
SOCKET g_ServerSocket = INVALID_SOCKET;

{ // Init winsock2
WSADATA wsaData;
memset(&wsaData, 0, sizeof(WSADATA));
int retVal = -1;
if( (retVal = WSAStartup(MAKEWORD(2,2), &wsaData)) != 0 ) {
cout << "WSAStartup Failed::Reason Code::"<< retVal << endl;
return 0;
}
}
{ // Create socket
g_ServerSocket = WSASocket(AF_INET,SOCK_STREAM, IPPROTO_TCP, NULL,0,WSA_FLAG_OVERLAPPED);
if( g_ServerSocket == INVALID_SOCKET ) {
cout << "Server Socket Creation Failed::Reason Code::" << WSAGetLastError() << endl;
return 0;
}
}


// connect
sockaddr_in service;
service.sin_family = AF_INET;
service.sin_addr.s_addr = inet_addr("127.0.0.1");
service.sin_port = htons(5600);
WSAConnect(g_ServerSocket, (SOCKADDR *)&service, sizeof(SOCKADDR), NULL, NULL, NULL, NULL);
{
int i = 0;
while (1)
{
if(i >= 50)
break;

char buffer[10];

//cin >> buffer ;
itoa(i, buffer, 10);
i++;

cout << buffer << endl;

if(strcmp(buffer, "exit") == 0)
break;

send(g_ServerSocket, buffer, sizeof(buffer), 1);

Sleep(500);
//recv(g_ServerSocket, buffer, sizeof(buffer), 1);
//cout << endl;
}
}
getchar();
closesocket(g_ServerSocket);
WSACleanup();

return 0;
}
...全文
191 9 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
wokagoka 2011-10-18
  • 打赏
  • 举报
回复
晕倒,我把MAX_BUFFER_SIZE从2048改为256就好了


谁能解释一下
wokagoka 2011-10-18
  • 打赏
  • 举报
回复
客户端逻辑:通过5600端口每个500毫秒发送50个数据包,然后结束

服务端逻辑:接收每个数据包并在服务端展示包内容
wokagoka 2011-10-18
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 lijianli9 的回复:]
你是开16客户端吗?
从代码里面看出来呀,应该是发送数据吧?
[/Quote]
只是一个客户端,连续发了50个数据包。服务端的前15个正常接收,第16个接收的只能接收IO_READ操作,在IO_READ操作中调用WSASend函数后,GetQueuedCompletionStatus应该获取到执行WSASend后的状态,然后继续往下执行,但是现在GetQueuedCompletionStatus居然变成了阻塞状态....

[Quote=引用 5 楼 smwhotjay 的回复:]
友情提示.网络上的很多iocp都是例子而已.不保证代码健壮安全性.不保证无bug.
所以还得靠自己.
iocp思想不难.就是异步.但要处理好各种情况.很难很麻烦.
[/Quote]
我只是想搞清楚IOCP的使用方法,遇到问题逐一解决,谢谢提醒
smwhotjay 2011-10-18
  • 打赏
  • 举报
回复

友情提示.网络上的很多iocp都是例子而已.不保证代码健壮安全性.不保证无bug.
所以还得靠自己.
iocp思想不难.就是异步.但要处理好各种情况.很难很麻烦.
lijianli9 2011-10-18
  • 打赏
  • 举报
回复
你是开16客户端吗?
从代码里面看出来呀,应该是发送数据吧?
wokagoka 2011-10-18
  • 打赏
  • 举报
回复
不懂就问,每个人都是这么走过来的
无视2楼

继续问
zhouzhipen 2011-10-18
  • 打赏
  • 举报
回复
网络中,人人平等,"跪求"二字不但出卖自己的尊严,还暴露了你连这最基本的网络知识都不知道!还搞什么IOCP.
wokagoka 2011-10-18
  • 打赏
  • 举报
回复
什么世道!~
自己顶吧
神的理想 2011-10-18
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 wokagoka 的回复:]
晕倒,我把MAX_BUFFER_SIZE从2048改为256就好了
谁能解释一下
[/Quote]
无法解释...
最近有项目要做一个高性能网络服务器,决定下功夫搞定完成端口IOCP),最终花了一个星期终于把它弄清楚了,并用C++写了一个版本,效率很不错。 但,从项目的总体需求来考虑,最终决定上.net平台,因此又花了一天一夜弄出了一个C#版,在这与大家分享。 一些心得体会: 1、在C#中,不用去面对完成端口的操作系统内核对象,Microsoft已经为我们提供了SocketAsyncEventArgs类,它封装了IOCP的使用。请参考:http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socketasynceventargs.aspx?cs-save-lang=1&cs-lang=cpp#code-snippet-1。 2、我的SocketAsyncEventArgsPool类使用List对象来存储对客户端来通信的SocketAsyncEventArgs对象,它相当于直接使用内核对象时的IoContext。我这样设计比用堆栈来实现的好处理是,我可以在SocketAsyncEventArgsPool池中找到任何一个与服务器连接的客户,主动向它发信息。而用堆栈来实现的话,要主动给客户发信息,则还要设计一个结构来存储已连接上服务器的客户。 3、对每一个客户端不管还发送还是接收,我使用同一个SocketAsyncEventArgs对象,对每一个客户端来说,通信是同步进行的,也就是说服务器高度保证同一个客户连接上要么在投递发送请求,并等待;或者是在投递接收请求,等待中。本例只做echo服务器,还未考虑由服务器主动向客户发送信息。 4、SocketAsyncEventArgs的UserToken被直接设定为被接受的客户端Socket。 5、没有使用BufferManager 类,因为我在初始化时给每一个SocketAsyncEventArgsPool中的对象分配一个缓冲区,发送时使用Arrary.Copy来进行字符拷贝,不去改变缓冲区的位置,只改变使用的长度,因此在下次投递接收请求时恢复缓冲区长度就可以了!如果要主动给客户发信息的话,可以new一个SocketAsyncEventArgs对象,或者在初始化中建立几个来专门用于主动发送信息,因为这种需求一般是进行信息群发,建立一个对象可以用于很多次信息发送,总体来看,这种花销不大,还减去了字符拷贝和消耗。 6、测试结果:(在我的笔记本上时行的,我的本本是T420 I7 8G内存) 100客户 100,000(十万次)不间的发送接收数据(发送和接收之间没有Sleep,就一个一循环,不的发送与接收) 耗时3004.6325 秒完成 总共 10,000,000 一千万次访问 平均每分完成 199,691.6 次发送与接收 平均每秒完成 3,328.2 次发送与接收 整个运行过程中,内存消耗在开始两三分种后就保持稳定不再增涨。 看了一下对每个客户端的延迟最多不超过2秒。

18,363

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧