pengzhenwanli 2005年03月18日
关于完成端口的程序。为什么在出现100个并发连接的时候,会出现系统错误?
#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 。对于完成端口,怎样处理多个客户端连接的数据?在一个线程内部还是再重新开线程,但是重新开的话,应该怎样开?在什么地方开?我现在使用一个连接一个线程的方式。这个在多个连接的情况下,系统出现很多问题。问题有点长,分数不过可以再加,也可以另给。谢谢大家
...全文
132 点赞 收藏 5
写回复
5 条回复

还没有回复,快来抢沙发~

发动态
发帖子
网络编程
创建于2007-09-28

7878

社区成员

6.4w+

社区内容

VC/MFC 网络编程
社区公告
暂无公告