首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C++ >

晓得 win32 tcpip iocp 的进来,求指导~

2013-01-11 
知道 win32 tcpip iocp 的进来,求指导~~问题描述:客户端发送文件去服务端,服务端采用iocp接收文件,正常情

知道 win32 tcpip iocp 的进来,求指导~~
问题描述:客户端发送文件去服务端,服务端采用iocp接收文件,正常情况客户端可发送文件完毕,但为了实现断点续传,中途需关闭客户端几次作为测试,这时服务端问题就来了,下面是iocp部分代码,问题基本已经缩小到一定范围,只是不知道怎么改,哪位哥们会的帮帮忙:



typedef enum
{
RECV_POSTED
} OPERATION_TYPE;

typedef struct
{
SOCKETms_Client;
charms_PathName[MAX_PATH];
CFile*ms_File;//接收文件

DWORDms_FileSize; // 文件大小
DWORDms_RecvedBytes; // 已接收大小

intms_FilePackageSize;//文件包大小
DWORDms_ProgressTimeInterval;//文件发送进度间隔时间
DWORDms_LastProgressTick;//文件进度最后统计时间
}RECV_IO_INFO, *LPRECV_IO_INFO;

typedef struct SPER_IO_OPERATION_DATA
{
WSAOVERLAPPED  overlap;
WSABUF         Buffer;
char           szMessage[MSGSIZE];
DWORD          NumberOfBytesRecvd;
SOCKADDR_IN   clientInfo;
RECV_IO_INFO   RecvIOInfo;
DWORD          Flags;
OPERATION_TYPE OperationType;
} PER_IO_OPERATION_DATA, *LPPER_IO_OPERATION_DATA;




int main(int argc, char* argv[])
{
WSADATA wsaData;
SOCKET sListen, sClient;
SOCKADDR_IN local, client;
DWORD i, dwThreadId;
int iAddrSize = sizeof(SOCKADDR_IN);
HANDLE CompletionPort = INVALID_HANDLE_VALUE;
SYSTEM_INFO sysinfo;
LPPER_IO_OPERATION_DATA lpPerIOData = NULL;


// Initialize windows socket library
memset(&wsaData,0,sizeof(WSADATA));

int nErrCode = 0;

if(wsaData.wVersion == 0)
{
nErrCode = WSAStartup(0x0202, &wsaData);
if(nErrCode != 0)
memset(&wsaData, 0, sizeof(WSADATA));
}


// Create completion port
CompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
// Create worker thread
GetSystemInfo(&sysinfo);
for (i = 0; i < sysinfo.dwNumberOfProcessors; i++)
{
CreateThread(NULL, 0, WorkerThread, CompletionPort, 0, &dwThreadId);
}
// Create listening socket
sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(sListen == INVALID_SOCKET)
{
CLogFile::WriteLog("创建监听套接字失败!");
return 0;
}



// Bind
local.sin_family = AF_INET;
local.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
local.sin_port = htons(PORT);



if(bind(sListen, (sockaddr*)&local, sizeof(SOCKADDR_IN)) != 0)
{
CLogFile::WriteLog("绑定失败!");
return 0;
}


// Listen
if(listen(sListen, SOMAXCONN) != 0)
{
CLogFile::WriteLog("监听失败");
return 0;
}
while (TRUE)
{
// Accept a connection
sClient = accept(sListen, (sockaddr*)&client, &iAddrSize);

if(sClient != INVALID_SOCKET)
{

printf("Accepted client:%s:%d\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port));
// Associate the newly arrived client socket with completion port
CreateIoCompletionPort((HANDLE)sClient, CompletionPort, (DWORD)sClient, 0);


// Launch an asynchronous operation for new arrived connection
lpPerIOData = (LPPER_IO_OPERATION_DATA)HeapAlloc(
GetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(PER_IO_OPERATION_DATA));
/*lpPerIOData =new SPER_IO_OPERATION_DATA;*/
lpPerIOData->clientInfo = client;
lpPerIOData->Buffer.len = MSGSIZE;
lpPerIOData->Buffer.buf = lpPerIOData->szMessage;
lpPerIOData->OperationType = RECV_POSTED;
lpPerIOData->RecvIOInfo.ms_File = new CFile;

WSARecv(sClient,
&lpPerIOData->Buffer,
1,
&lpPerIOData->NumberOfBytesRecvd,
&lpPerIOData->Flags,
&lpPerIOData->overlap,
NULL);
}else
{
CLogFile::WriteLog("发生一个错误的连接客户端!");
}


}
PostQueuedCompletionStatus(CompletionPort, 0xFFFFFFFF, 0, NULL);
CloseHandle(CompletionPort);
closesocket(sListen);


if(wsaData.wVersion != 0)
WSACleanup();

memset(&wsaData,0,sizeof(WSADATA));
return 0;
}

DWORD WINAPI WorkerThread(LPVOID CompletionPortID)
{
HANDLECompletionPort = (HANDLE)CompletionPortID;
DWORDdwBytesTransferred;
LPPER_IO_OPERATION_DATA lpPerIOData = NULL;

SOCKET sClient;

while (TRUE)
{

if(GetQueuedCompletionStatus(
CompletionPort,
&dwBytesTransferred,
(DWORD*)&sClient,
(LPOVERLAPPED*)&lpPerIOData,
INFINITE) == 0)
{
                        //问题好像就出在这个函数里?感觉什么东西释放错误,导致接收端崩溃,其他客户端也无法连接。
int nErr = WSAGetLastError();
if(nErr == WSAECONNRESET)
{
CLogFile::WriteLog("GetQueuedCompletionStatus等待数据失败!WSAECONNRESET");


}else
{
CLogFile::WriteLog("GetQueuedCompletionStatus等待数据失败!有客户端接收数据错误,正常退出");

}
//销毁文件对象
if(lpPerIOData->RecvIOInfo.ms_File != NULL)
delete(lpPerIOData->RecvIOInfo.ms_File);
closesocket(sClient);
HeapFree(GetProcessHeap(), 0, lpPerIOData);
return 0;
}
if (dwBytesTransferred == 0xFFFFFFFF)
{
CLogFile::WriteLog("有客户端发送0xFFFFFFFF数据!");
//销毁文件对象
if(lpPerIOData->RecvIOInfo.ms_File != NULL)
delete(lpPerIOData->RecvIOInfo.ms_File);
closesocket(sClient);
HeapFree(GetProcessHeap(), 0, lpPerIOData);
return 0;
}
if (dwBytesTransferred == SOCKET_ERROR)
{

//销毁文件对象
if(lpPerIOData->RecvIOInfo.ms_File != NULL)
delete(lpPerIOData->RecvIOInfo.ms_File);
closesocket(sClient);
HeapFree(GetProcessHeap(), 0, lpPerIOData);
return 0;
}
if (lpPerIOData->OperationType == RECV_POSTED)
{
if (dwBytesTransferred == 0)
{
// Connection was closed by client
printf("Leaved   client:%s:%d\n", inet_ntoa(lpPerIOData->clientInfo.sin_addr), ntohs(lpPerIOData->clientInfo.sin_port));
//销毁文件对象
delete(lpPerIOData->RecvIOInfo.ms_File);
closesocket(sClient);
HeapFree(GetProcessHeap(), 0, lpPerIOData);
}
else
{
lpPerIOData->szMessage[dwBytesTransferred] = '\0';
lpPerIOData->RecvIOInfo.ms_Client = sClient;


DoRecv(&lpPerIOData->RecvIOInfo,lpPerIOData->szMessage,dwBytesTransferred);
// Launch another asynchronous operation for sClient
//memset(lpPerIOData, 0, sizeof(PER_IO_OPERATION_DATA));
memset(lpPerIOData->szMessage, 0, MSGSIZE);
lpPerIOData->Buffer.len = MSGSIZE;
lpPerIOData->Buffer.buf = lpPerIOData->szMessage;
lpPerIOData->OperationType = RECV_POSTED;
WSARecv(sClient,
&lpPerIOData->Buffer,
1,
&lpPerIOData->NumberOfBytesRecvd,
&lpPerIOData->Flags,
&lpPerIOData->overlap,
NULL);
}
}
}
return 0;
}


[解决办法]
if(GetQueuedCompletionStatus(...) == 0)
这里面为什么要return 0 啊?
这样线程不就结束了么?下次再有连接进来你重新创建线程?

if (dwBytesTransferred == SOCKET_ERROR)?
传输字节数 与 SOCKET_ERROR判断是什么意思?SOCKET_ERROR好像是-1吧



引用:
C/C++ code?123                WSARecv(sClient,&amp;lpPerIOData->Buffer, 1, &amp;lpPerIOData->NumberOfBytesRecvd,&amp;lpPerIOData->Flags,&amp;lpPerIOData->overlap, NULL);getlasterror();//这……


这个997是正常的

热点排行