套接字完成端口模型的一个问题?

ldcsoftware 2008-03-18 05:26:43
#include <winsock2.h>
#include <windows.h>
#include <stdio.h>

#define PORT 5150
#define DATA_BUFSIZE 8192

typedef struct
{
OVERLAPPED Overlapped;
WSABUF DataBuf;
CHAR Buffer[DATA_BUFSIZE];
DWORD BytesSEND;
DWORD BytesRECV;
}PER_IO_OPERATION_DATA,* LPPER_IO_OPERATION_DATA;

typedef struct
{
SOCKET Socket;
}PER_HANDLE_DATA,* LPPER_HANDLE_DATA;

DWORD WINAPI ServerWorkerThread(LPVOID CompletionPortID);

void main(void)
{
SOCKADDR_IN InternetAddr;
SOCKET Listen;
SOCKET Accept;
HANDLE CompletionPort;
SYSTEM_INFO SystemInfo;
int i;
DWORD RecvBytes;
DWORD Flags;
DWORD ThreadID;
WSADATA wsaData;
DWORD Ret;

if((Ret = WSAStartup(0x0202,&wsaData)) != 0)
{
printf("WSAStartup failed with error %d\n",Ret);
return ;
}

if((CompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0)) == NULL)
{
printf("CreateIoCompletionPort() failed with error %d\n",GetLastError());
return;
}

GetSystemInfo(&SystemInfo);

for(i = 0;i < SystemInfo.dwNumberOfProcessors * 2;i++)
{
HANDLE ThreadHandle;
printf("在创建线程之中\n");
if((ThreadHandle = CreateThread(NULL,0,ServerWorkerThread,CompletionPort,0,&ThreadID)) == NULL)
{
printf("CreateThread() failed with error %d\n",GetLastError());
return;
}
CloseHandle(ThreadHandle);
}

if((Listen = WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)
{
printf("WSASocket() failed with error %d\n",WSAGetLastError());
return ;
}

InternetAddr.sin_family = AF_INET;
InternetAddr.sin_addr.s_addr = htonl(INADDR_ANY);
InternetAddr.sin_port = htons(PORT);

if(bind(Listen,(PSOCKADDR)&InternetAddr,sizeof(InternetAddr)) == SOCKET_ERROR)
{
printf("bind() failed with error %d\n",WSAGetLastError());
return ;
}

if(listen(Listen,5) == SOCKET_ERROR)
{
printf("listen() failed with error %d\n",WSAGetLastError());
return;
}

while(TRUE)
{
printf("在Accept之前\n");
if((Accept = WSAAccept(Listen,NULL,NULL,NULL,0)) == SOCKET_ERROR)
{
printf("WSAAccept() failed with error %d\n",WSAGetLastError());
return ;
}
printf("在Accept之后\n");

if((PerHandleData = (LPPER_HANDLE_DATA)GlobalAlloc(GPTR,sizeof(PER_HANDLE_DATA))) == NULL)
{
printf("GlabalAlloc() failed with error %d\n",GetLastError());
return;
}

printf("Socket number %d connected\n",Accept);
PerHandleData->Socket = Accept;
if(CreateIoCompletionPort((HANDLE)Accept,CompletionPort,(DWORD)PerHandleData,0) == NULL)
{
printf("CreateIoCompletionPort failed with error %d\n",GetLastError());
return ;
}

if((PerIoData = (LPPER_IO_OPERATION_DATA)GlobalAlloc(GPTR,sizeof(PER_IO_OPERATION_DATA))) == NULL)
{
printf("GlobalAlloc() failed with error %d\n",GetLastError());
return;
}

ZeroMemory(&(PerIoData->Overlapped),sizeof(OVERLAPPED));
PerIoData->BytesSEND = 0;
PerIoData->BytesRECV = 0;
PerIoData->DataBuf.len = DATA_BUFSIZE;
PerIoData->DataBuf.buf = PerIoData->Buffer;

Flags = 0;
if(WSARecv(Accept,&(PerIoData->DataBuf),1,&RecvBytes,&Flags,&(PerIoData->Overlapped),NULL) == SOCKET_ERROR)
{
if(WSAGetLastError() != ERROR_IO_PENDING)
{
printf("WSARecv() failed with error %d \n",WSAGetLastError());
return;
}
}
printf("the result is %s\n",PerIoData->DataBuf.buf);
}
}

DWORD WINAPI ServerWorkerThread(LPVOID CompletionPortID)
{
HANDLE CompletionPort = (HANDLE)CompletionPortID;
DWORD BytesTransferred;
LPOVERLAPPED Overlapped;
LPPER_HANDLE_DATA PerHandleData;
LPPER_IO_OPERATION_DATA PerIoData;
DWORD SendBytes, RecvBytes;
DWORD Flags;

while(TRUE)
{
printf("在GetQueuedCompletionStatues之前\n");

if(GetQueuedCompletionStatus(CompletionPort,&BytesTransferred,(LPDWORD)&PerHandleData,(LPOVERLAPPED*)&PerIoData,INFINITE) == 0)
{
printf("GetQueuedCompletionStatus() failed with error %d\n",GetLastError());
// return 0;
}
printf("在GetQueuedCompletionStatus之后\n");

if(BytesTransferred == 0)
{
printf("Closing socket %d\n",PerHandleData->Socket);
if(closesocket(PerHandleData->Socket) == SOCKET_ERROR)
{
printf("closesocket() failed with error %d\n",WSAGetLastError());
return 0;
}
GlobalFree(PerHandleData);
GlobalFree(PerIoData);
continue;
}
if(PerIoData->BytesRECV == 0)
{
printf("BytesRECV\n");
PerIoData->BytesRECV = BytesTransferred;
PerIoData->BytesSEND = 0;
}
else
{
printf("BytesRECV else\n");
PerIoData->BytesSEND += BytesTransferred;
}
if(PerIoData->BytesRECV > PerIoData->BytesSEND) // 问题就在这里问题就在这里问题就在这里问题就在这里问题就在这里问题就在这里问题就在这里问题就在这里问题就在这里问题就在这里
{
printf("BytesRECV > BytesSEND)\n");
ZeroMemory(&(PerIoData->Overlapped),sizeof(OVERLAPPED));

PerIoData->DataBuf.buf = PerIoData->Buffer + PerIoData->BytesSEND;
PerIoData->DataBuf.len = PerIoData->BytesRECV - PerIoData->BytesSEND;

if(WSASend(PerHandleData->Socket,&(PerIoData->DataBuf),1,&SendBytes,0,&(PerIoData->Overlapped),NULL) == SOCKET_ERROR)
{
if(WSAGetLastError() != ERROR_IO_PENDING)
{
printf("WSASend() failed with error %d\n",WSAGetLastError());
return 0;
}
}
}
else
{
printf("recv\n");
PerIoData->BytesRECV = 0;
Flags = 0;
ZeroMemory(&(PerIoData->Overlapped),sizeof(OVERLAPPED));

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

if(WSARecv(PerHandleData->Socket,&(PerIoData->DataBuf),1,&RecvBytes,&Flags,&(PerIoData->Overlapped),NULL) == SOCKET_ERROR)
{
if(WSAGetLastError() != ERROR_IO_PENDING)
{
printf("WSARecv() failed with error %d\n",WSAGetLastError());
return 0;
}
}
printf("在recv之后\n");
}
printf("在while循环之后\n");
}
printf("在while循环之外\n");
}


请认真看看这个例子,上面有问题的地方我有注释。
为什么那里用if(PerIoData->BytesRECV > PerIoData->BytesSEND),这样不是只能发送一次数据吗?如果数据没有发送完毕,它就要再循环一次。
那么到了GetQueuedCompletionStatus,它不是要停下来吗?这个函数不是要等待从主线程中的数据的到达?那么它之后的代码不就运行不了了。
...全文
75 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

64,849

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

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