套接字完成端口模型的一个问题
#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;
LPPER_HANDLE_DATA PerHandleData;
LPPER_IO_OPERATION_DATA PerIoData;
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");
}
我感觉那行应该是用while,后面再修改一下,这样才能保证数据全都发送出去了;
用if的话不是只能发送一次吗?即使外面有一个while循环,但是它到了GetQueuedCompletionStatus不是停下来了吗(前面又没有新的数据到来)。
希望有人能回答我下,这个问题困扰了我好久。 谢谢
[[it] 本帖最后由 ldcsoftware 于 2008-3-18 11:21 编辑 [/it]]