求教:完成端口同时处理多个连接时服务端内存不能为Read

tianya550066 2010-04-07 01:19:53
客户端要向服务端发送两类数据
(1)feedback 反馈信息8K以内
(2)dumpfile  出错文件

每次发送8K,头部(64Byte)包含数据类型,‘A’则为反馈信息,‘B’则为出错文件。
头部的后63位包含要保存的文件名。后面8192-64B为数据。(这种处理应该很糟糕,但对iocp不熟,一时想不到更好的办法了)

现在服务端处理同时多个请求时,会出现内存不能为Read的错误。
折腾半天搞不定,前来请教一下,谢谢。


//#include "afx.h"
#pragma comment(lib,"ws2_32.lib")
#include <stdio.h>
#include <memory.h>
#include <winsock2.h>
#include <iostream>
#include <fstream>
#include <string>
using namespace std;

#define RECV_POSTED 1001
#define SEND_POSTED 1002
#define DATA_BUFSIZE 8192

CRITICAL_SECTION g_cs;//使用临界区对象处理线程同步文件操作

struct packHead
{
char mark;
char filename[63];
};

int Init();

HANDLE hCompletionPort;
typedef struct _PER_HANDLE_DATA
{
SOCKET sock;
//char filepath[256];
}PER_HANDLE_DATA,* LPPER_HANDLE_DATA;

typedef struct _PER_IO_OPERATION_DATA
{
OVERLAPPED Overlapped;
WSABUF DataBuff[1];
char Buff[DATA_BUFSIZE];
BOOL OperationType;
}PER_IO_OPERATION_DATA,* LPPER_IO_OPERATION_DATA;

DWORD WINAPI ServerWorkerThread(LPVOID CompletionPort);

int main(int argc, char* argv[])
{
LPPER_HANDLE_DATA perHandleData;
LPPER_IO_OPERATION_DATA ioperdata;
SYSTEM_INFO siSys;
SOCKET sockListen;
struct sockaddr_in addrLocal;
//char buf[24];
int nRet = 0;
DWORD nThreadID;
SOCKET sockAccept;
// DWORD dwFlags;
DWORD dwRecvBytes;
int nReuseAddr = 1;
int i;

::InitializeCriticalSection(&g_cs);


cout<<"服务器启动..."<<endl;
if(Init() != 0) return 1;

//创建一个IO完成端口

hCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0);
if(hCompletionPort == INVALID_HANDLE_VALUE)
{
cout<<"创建IO完成端口失败"<<endl;
return 1;
}

GetSystemInfo(&siSys);

for( i = 0;i<(int)siSys.dwNumberOfProcessors*2;i++)//NumberOfProcessors
{
HANDLE hThread;
hThread = CreateThread(NULL,0,ServerWorkerThread,(LPVOID)hCompletionPort,0,&nThreadID);

CloseHandle(hThread);
}

sockListen = WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED);
if(sockListen == SOCKET_ERROR)
{
cout<<"WSASocket错误"<<endl;
return 1;
}

if(setsockopt(sockListen,SOL_SOCKET,SO_REUSEADDR,(const char *)&nReuseAddr,sizeof(int)) != 0)
{
cout<<"setsockopt错误"<<endl;
return 1;
}
addrLocal.sin_family = AF_INET;
addrLocal.sin_addr.s_addr = htonl(INADDR_ANY);
addrLocal.sin_port = htons(5150);
if(bind(sockListen,(struct sockaddr *)&addrLocal,sizeof(sockaddr_in)) != 0)
{
cout<<"bind错误"<<endl;
int n = WSAGetLastError();
return 1;
}

if(listen(sockListen,5)!=0)
{
cout<<"listen错误"<<endl;
return 1;
}
while(true)
{

sockAccept = WSAAccept(sockListen,NULL,NULL,NULL,0);
perHandleData = (LPPER_HANDLE_DATA)GlobalAlloc(GPTR,sizeof(PER_HANDLE_DATA));
if(perHandleData == NULL)
continue;
cout<<"socket number "<<sockAccept<<"接入"<<endl;
Sleep(10);///////////////////重要:建立连接后等待几毫秒让客户端传完第一个8192(1460per)
perHandleData->sock = sockAccept;

ioperdata = (LPPER_IO_OPERATION_DATA)GlobalAlloc(GPTR,sizeof(PER_IO_OPERATION_DATA));
memset(&(ioperdata->Overlapped),0,sizeof(OVERLAPPED));
(ioperdata->DataBuff[0]).len = DATA_BUFSIZE;
(ioperdata->DataBuff[0]).buf = ioperdata->Buff;
ioperdata->OperationType = RECV_POSTED;
if( ioperdata == NULL)
{
free(perHandleData);
continue;
}
//关联
//cout<<"关联SOCKET"<<sockAccept<<"和完成端口"<<endl;
if(CreateIoCompletionPort((HANDLE)sockAccept,hCompletionPort,(DWORD)perHandleData,0) == NULL)
{
cout<<sockAccept<<"createiocompletionport错误"<<endl;
free(perHandleData);
free(ioperdata);
continue;
}
//投递接收操作
//cout<<"投递接收操作"<<endl;
//WSARecv(perHandleData->sock,ioperdata->DataBuff,1,&dwRecvBytes,&dwFlags,&(ioperdata->Overlapped),NULL);


DWORD Flags=0;
if (WSARecv(sockAccept, &(ioperdata->DataBuff[0]), 1, &dwRecvBytes, &Flags,
&(ioperdata->Overlapped), NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() != ERROR_IO_PENDING)
{
printf("WSARecv() failed with error %d\n", WSAGetLastError());
return 1;
}
}
}

::DeleteCriticalSection(&g_cs);
return 0;
}
//---------------------------------------------------------------------------
int Init()
{
WSAData wsaData;
if(WSAStartup(MAKEWORD(2,2),&wsaData) != 0)
{
cout<<"WSAStartup失败"<<endl;
return -1;
}

if(LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
{
cout<<"SOCKET版本不对"<<endl;
WSACleanup();
return -1;
}
return 0;
}

DWORD WINAPI ServerWorkerThread(LPVOID CompletionPort)
{
//DWORD id=GetCurrentThreadId();
//cout<<id<<endl;
HANDLE ComPort = (HANDLE)CompletionPort;
DWORD BytesTransferred;
// LPOVERLAPPED Overlapped;
LPPER_HANDLE_DATA PerHandleData;
LPPER_IO_OPERATION_DATA PerIoData;
DWORD RecvBytes;//,SendBytes;
DWORD Flags;
BOOL bT;
//bool bFirst=true;//标记第一次循环






while(TRUE)
{



//cout<<"线程id:"<<id<<endl;
//cout<<"socket: "<<PerHandleData->sock<<endl;
//cout<<"filepath: "<<(char*)PerHandleData->filepath<<endl;
//等待完成端口上SOCKET的完成
//cout<<"等待完成端口上SOCKET的完成"<<endl;
bT = GetQueuedCompletionStatus(ComPort,
&BytesTransferred,(LPDWORD)&PerHandleData,
(LPOVERLAPPED *)&PerIoData,INFINITE);

if (bT==0)
{
cout<<"GetQueuedCompletionStatus filed with error: "<<GetLastError()<<endl;
return 0;
}


//cout<<"处理io请求"<<endl;

//检查是否有错误产生
if(BytesTransferred == 0 &&
(PerIoData->OperationType == RECV_POSTED ||
PerIoData->OperationType == SEND_POSTED))
{
cout<<"线程id:"<<GetCurrentThreadId()<<endl;
//关闭SOCKET
cout<<"文件传输完毕"<<endl;
//cout<<endl;
cout<<"socket "<<PerHandleData->sock<<" 关闭"<<endl;
cout<<endl;
//closesocket(PerHandleData->sock);

if (closesocket(PerHandleData->sock) == SOCKET_ERROR)
{
printf("closesocket() failed with error %d\n", WSAGetLastError());
return 0;
}
//bFirst=true;

GlobalFree(PerHandleData);
GlobalFree(PerIoData);
continue;
}

//为请求服务

if(PerIoData->OperationType == RECV_POSTED)
{
packHead head;
memcpy(&head,PerIoData->Buff,64);
if (head.mark=='A')
{
string temp("C:\\feedback");//接收反馈信息8K以内
temp+="\\";
temp+=head.filename;
//cout<<"Filepath:"<<temp<<endl;

::EnterCriticalSection(&g_cs);

ofstream os(temp.c_str());
os.write(PerIoData->Buff+64,BytesTransferred-64);
os.close();

::LeaveCriticalSection(&g_cs);


}
if (head.mark=='B')
{
string temp("C:\\dumpfile");//接收出错文件
temp+="\\";
temp+=head.filename;


::EnterCriticalSection(&g_cs);

ofstream os(temp.c_str(),ios::binary | ios::app);
os.write(PerIoData->Buff+64,BytesTransferred-64);
os.close();


::LeaveCriticalSection(&g_cs);
//cout<<PerHandleData->sock<<" : "<<BytesTransferred<<endl;
Sleep(3);


}

Flags = 0;
ZeroMemory((LPVOID)&(PerIoData->Overlapped),sizeof(OVERLAPPED));
ZeroMemory(PerIoData->Buff,DATA_BUFSIZE);
PerIoData->DataBuff[0].len = DATA_BUFSIZE;
PerIoData->DataBuff[0].buf = PerIoData->Buff;
PerIoData->OperationType = RECV_POSTED;
WSARecv(PerHandleData->sock,PerIoData->DataBuff,
1,&RecvBytes,&Flags,&(PerIoData->Overlapped),NULL);
}

}
}

...全文
117 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
tianya550066 2010-04-07
  • 打赏
  • 举报
回复
嗯,谢谢。
zhou1xp 2010-04-07
  • 打赏
  • 举报
回复
楼主去查点资料吧,这个要说清楚比较难,我自己理解都不是很全哈
tianya550066 2010-04-07
  • 打赏
  • 举报
回复
呃,是有点似懂非懂的感觉。
就是说WSARecv(PerHandleData->sock,PerIoData->DataBuff,1,&RecvBytes,&Flags,&(PerIoData->Overlapped),NULL);
投递接收操作时,这里的PerHandleData->sock 是从完成端口的序列中获得的,不是他本身确定的对吧。


//我原来以为,一个socket连接进来时,PerHandleData->sock就是针对他固定不变的。
zhou1xp 2010-04-07
  • 打赏
  • 举报
回复
。。。。。。。,楼主你没有理解完成端口的机制,处理完成后应该再次设置并投递,而且一般来说socket也不是无限制的生成的
tianya550066 2010-04-07
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 zhou1xp 的回复:]

你一共建立了多少Socket,大概多久一个Socket可以成为完成状态然后再从新投递到完成端口的序列中
[/Quote]
有多少个用户连接上来就有多少个socket,请求处理完了就closesocket了。

对一个socket每接收完一个8192B,就再投递一个WSARecv.
zhou1xp 2010-04-07
  • 打赏
  • 举报
回复
你一共建立了多少Socket,大概多久一个Socket可以成为完成状态然后再从新投递到完成端口的序列中
tianya550066 2010-04-07
  • 打赏
  • 举报
回复
不应该是‘位’,应该是BYTE。
tianya550066 2010-04-07
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 zhou1xp 的回复:]

楼主能不能把你的大概思路写下,代码比较多
[/Quote]

谢谢,好的。
客户端就是简单的send()。一次发8192B。
服务端就一直投递接收请求。
再根据8192B的第一位决定是feedback('A')还是dumpfile('B');
第二位到第64位是文件名(由用户名+时间组成,这个在客户端处理的),服务端根据文件名建立文件。
就是说每个8192B都要判断一下,这样应该很糟糕。

可现在主要的问题就是服务端同时处理二,三个文件请求时就内存不能Read.

zhou1xp 2010-04-07
  • 打赏
  • 举报
回复
楼主能不能把你的大概思路写下,代码比较多
tianya550066 2010-04-07
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 vincent_1011 的回复:]

人家有说了,太多pending IO,全把内存锁住了,貌似有些人是投递了0内存 recv来解决。
[/Quote]

能否详细点呀。
我只要在本地测试的呀,同时发送三个文件,服务端就内存不能为read。
vincent_1011 2010-04-07
  • 打赏
  • 举报
回复
人家有说了,太多pending IO,全把内存锁住了,貌似有些人是投递了0内存 recv来解决。

18,356

社区成员

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

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