关于完成端口的程序。为什么在出现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 。对于完成端口,怎样处理多个客户端连接的数据?在一个线程内部还是再重新开线程,但是重新开的话,应该怎样开?在什么地方开?我现在使用一个连接一个线程的方式。这个在多个连接的情况下,系统出现很多问题。问题有点长,分数不过可以再加,也可以另给。谢谢大家。
这个问题在VC版问过了,不知道咱们C/C++版能否给出满意的回答。