关于完成端口的程序。为什么在出现100个并发连接的时候,会出现系统错误?在网络版问过了,不知道咱们版能否给出回答

pengzhenwanli 2005-03-18 08:03:22
#include <stdio.h>
#include <iostream>
#include <winsock2.h>


#define DATA_BUFSIZE 4
//#define PACKAGE_SIZE 4

using namespace std;

typedef enum _PER_IO_OPERATION_TYPE
{
RECV_POSTED,
SEND_POSTED,
}PerIoOperationType;

typedef struct _PER_HANDLE_DATA
{
SOCKET Socket;
SOCKADDR_STORAGE ClientAddr;
}PER_HANDLE_DATA,*LPPER_HANDLE_DATA;
typedef struct
{
OVERLAPPED Overlapped;
char Buffer[DATA_BUFSIZE];
int BufferLen;
PerIoOperationType OperationType;
WSABUF DataBuf;
}PER_IO_DATA,*LPPER_IO_DATA;

DWORD WINAPI ServerWorkerThread(LPVOID CompletionPortID);

int main()
{
HANDLE hCompletionPort;
WSADATA wsd;
SYSTEM_INFO SystemInfo;

SOCKET listeningSocket;
SOCKADDR_IN serverAddr;


int i;


DWORD flags = 0;
int port = 5150;
int nResult;
DWORD recvBytes;
WSAStartup(MAKEWORD(2,2),&wsd);

hCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0);
GetSystemInfo(&SystemInfo);

//根据网上人说,MSDN的建议,创建的线程数为CPU*2+2
for(i=0;i<SystemInfo.dwNumberOfProcessors;i++)
{
HANDLE ThreadHandle;
ThreadHandle = CreateThread(NULL,0,ServerWorkerThread,hCompletionPort,i,NULL);
//CloseHandle(ThreadHandle);
}


listeningSocket = WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED);

serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(port);
serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);

bind(listeningSocket,(PSOCKADDR)&serverAddr,sizeof(serverAddr));

listen(listeningSocket,5);

SOCKADDR_IN clientAddr;

int clientAddrLen = sizeof(clientAddr);

SOCKET newConnect;
LPPER_IO_DATA PerIoData = NULL;
PER_HANDLE_DATA *PerHandleData = NULL;

while(true)
{
newConnect = accept(listeningSocket,(SOCKADDR*)&clientAddr,&clientAddrLen);

PerHandleData = (LPPER_HANDLE_DATA) GlobalAlloc(GPTR,sizeof(PER_HANDLE_DATA));;

PerIoData = (LPPER_IO_DATA)GlobalAlloc(GPTR,sizeof(PER_IO_DATA));

printf("Socket number %d connected \n",newConnect);

//传入连接的socket
PerHandleData->Socket = newConnect;

HANDLE h = CreateIoCompletionPort((HANDLE)newConnect,hCompletionPort,(DWORD)PerHandleData,0);
if(h==NULL)
{
cout << "Error" << endl;
}
//这里的思想其实一样,服务器上来只做接收,并不发送,发送数据再接收数据之后
//当接收数据后判断接受的是什么数据

ZeroMemory(&(PerIoData->Overlapped),sizeof(OVERLAPPED));

PerIoData->DataBuf.len = DATA_BUFSIZE;
PerIoData->DataBuf.buf = PerIoData->Buffer;
PerIoData->OperationType = RECV_POSTED;

nResult = WSARecv(newConnect,
&(PerIoData->DataBuf),
1,
&recvBytes,
&flags,
&(PerIoData->Overlapped),
NULL);

cout << nResult << endl;
cout << WSAGetLastError()<< endl;

}
WSACleanup();
}
DWORD WINAPI ServerWorkerThread(LPVOID CompletionPortID)
{
HANDLE CompletionPort = (HANDLE)CompletionPortID;
DWORD BytesTransferred;
LPPER_HANDLE_DATA PerHandleData;

LPPER_IO_DATA PerIoData;
DWORD Flags = 0;
BOOL result;

DWORD RecvBytes;
DWORD SendBytes;

while(true)
{
result = GetQueuedCompletionStatus(CompletionPort,
&BytesTransferred,
(LPDWORD)&PerHandleData,
(LPOVERLAPPED*)&PerIoData,
INFINITE);

if(result==0)
{
cout << "error" << endl;
}

if(BytesTransferred==0)
{
closesocket(PerHandleData->Socket);
GlobalFree(PerHandleData);
GlobalFree(PerIoData);
cout << "close" << endl;
continue;
}

if(PerIoData->OperationType == RECV_POSTED)
{
//接收的数目,如果小于包大小,再次接收等待
//if(BytesTransferred!=PACKAGE_SIZE)
//{
//cout << BytesTransferred << endl;
//}
int *i = (int*)PerIoData->DataBuf.buf;
++(*i);
ZeroMemory(&(PerIoData->Overlapped),sizeof(OVERLAPPED));
PerIoData->DataBuf.len = sizeof(int);
PerIoData->DataBuf.buf = (char*)i;
PerIoData->OperationType = SEND_POSTED;

WSASend(PerHandleData->Socket,
&(PerIoData->DataBuf), 1, &SendBytes,
Flags, &(PerIoData->Overlapped), NULL);
}

if(PerIoData->OperationType == SEND_POSTED)
{
//发送的数目,如果没有发送完全,则再次发送
Flags = 0;
// Set up the per-I/O operation data for the next
// overlapped call
ZeroMemory(&(PerIoData->Overlapped),sizeof(OVERLAPPED));
PerIoData->DataBuf.len = DATA_BUFSIZE;
PerIoData->DataBuf.buf = PerIoData->Buffer;
PerIoData->OperationType = RECV_POSTED;
WSARecv(PerHandleData->Socket,
&(PerIoData->DataBuf), 1, &RecvBytes,
&Flags, &(PerIoData->Overlapped), NULL);
}
}

return 0;
}
这个是服务器程序。客户端使用多线程来模拟,达到100左右的时候,会出现系统错误。如果连接数少的话,没事。请教一下,完成端口应该怎样来写?上面的程序应该是windows网络编程上的例子更改的。如果大家有现成的完成端口的例子,可以发到我的邮箱.ziqiriying@163.com 。对于完成端口,怎样处理多个客户端连接的数据?在一个线程内部还是再重新开线程,但是重新开的话,应该怎样开?在什么地方开?我现在使用一个连接一个线程的方式。这个在多个连接的情况下,系统出现很多问题。问题有点长,分数不过可以再加,也可以另给。谢谢大家。
这个问题在VC版问过了,不知道咱们C/C++版能否给出满意的回答。
...全文
289 11 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
keqi 2005-04-03
  • 打赏
  • 举报
回复
和下面的内存申请、释放有关。

PerHandleData = (LPPER_HANDLE_DATA) GlobalAlloc(GPTR,sizeof(PER_HANDLE_DATA));;

PerIoData = (LPPER_IO_DATA)GlobalAlloc(GPTR,sizeof(PER_IO_DATA);

应改造成单向链表方式管理内存。研究一下例子吧。

还有本书比较详细介绍了完成端口:
《Winsock2网络编程实用教程》 清华大学出版社的
pengzhenwanli 2005-03-29
  • 打赏
  • 举报
回复
用完成端口不能使用单线程。
但是现在就两个线程。应该不是线程的问题。
heroboy2000 2005-03-28
  • 打赏
  • 举报
回复
简易楼主先把程序改成单线程的,看看有没有错,因为我想大部分的错误是因为线程的同步与互斥造成的,而不是完成端口。
dieken_qfz 2005-03-26
  • 打赏
  • 举报
回复
这个信息不知道对你有没有用处,记得看过一个有关BitTorrent的文章,
说windows对连接数有限制,具体限制的数值好像是在注册表里头。
zxxpro 2005-03-24
  • 打赏
  • 举报
回复
对网络不了解,帮楼住顶一下了!!!!!
keqi 2005-03-24
  • 打赏
  • 举报
回复
不是说完成端口不支持多用户并发连接,而是书上只是通过一个套接字举一个完成端口的例子而已,具体支持多套接字的程序需要自己扩展。

网上有不少完成端口的例子。比如下面的链接,就包含一个完成端口服务器的完整源码。
http://www.ddvip.net/program/vc/index1/56.htm
yjh1982 2005-03-21
  • 打赏
  • 举报
回复
完成端口应该最少的话单线程就可以了吧
pengzhenwanli 2005-03-21
  • 打赏
  • 举报
回复
怎么没有人看帖子阿?
keqi 2005-03-19
  • 打赏
  • 举报
回复
hCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0);
GetSystemInfo(&SystemInfo);

//根据网上人说,MSDN的建议,创建的线程数为CPU*2+2
for(i=0;i<SystemInfo.dwNumberOfProcessors;i++)
{
HANDLE ThreadHandle;
ThreadHandle = CreateThread(NULL,0,ServerWorkerThread,hCompletionPort,i,NULL);
//CloseHandle(ThreadHandle);
}


CreateIoCompletionPort开始建立完成端口的时候,最后一个参数控制了一个完成端口上工作者线程的最大数量,用了0表示1个cpu最多只有一个工作者线程。开始时可能工作者线程超过这个数目,这是《windows网络编程》书中的说明。

所以下面开了许多工作者线程没有必要。

另外,书上的这个例子根本不支持多client的连接。

需要使用至少数组的形式定义PER_HANDLE_DATA,PER_IO_DATA,连上来一个重新分配内存。

比较好的用法是用单链表或双向链表,高级用法是用lookasidelist。
pengzhenwanli 2005-03-19
  • 打赏
  • 举报
回复
楼上的,如果支持多client连接,完成端口的意义何在?
我这个是windows网络编程第二版上的
YFY 2005-03-18
  • 打赏
  • 举报
回复
先顶加入,明天再看^_^

24,860

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 工具平台和程序库
社区管理员
  • 工具平台和程序库社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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