关于重叠I/O完成例程

fresh_ 2001-04-28 11:55:00
在csdn精品图书中下载的《网络编程》原码Chapter08\Callback\callback.cpp中,
DWORD WINAPI WorkerThread(LPVOID lpParameter)
{
...
while(true)
{
WSAWaitForMultipleEvents(1, EventArray, FALSE, WSA_INFINITE, TRUE);
...
WSARecv(SocketInfo->Socket, &(SocketInfo->DataBuf), 1, &RecvBytes,&Flags,&(SocketInfo->Overlapped), WorkerRoutine);
...
}
}
void CALLBACK WorkerRoutine(DWORD Error, DWORD BytesTransferred,
LPWSAOVERLAPPED Overlapped, DWORD InFlags)
{
...
WSASend(SI->Socket, &(SI->DataBuf), 1, &SendBytes,&(SI->Overlapped), WorkerRoutine);
...
}
其中某一客户端connect时触发服务端EventArray后,服务端WSAWaitForMultipleEvents返回,接着执行WSARecv,再回到WSAWaitForMultipleEvents等待;
当客户端send后,服务端干了两件事:
1、使WSAWaitForMultipleEvents再次返回;
2、服务端重叠I/O完成例程WorkerRoutine被执行。
因为WorkerRoutine中调用了WSASend。当WSASend完成后,我认为服务端仍然要干两件事:
1、服务端重叠I/O完成例程WorkerRoutine应该再次被执行,这没错。
2、使WSAWaitForMultipleEvents应该返回,可程序并没这样,为什么?
...全文
211 2 打赏 收藏 转发到动态 举报
写回复
用AI写文章
2 条回复
切换为时间正序
请发表友善的回复…
发表回复
fresh_ 2001-04-28
  • 打赏
  • 举报
回复
#include <winsock2.h>
#include <windows.h>
#include <stdio.h>

#define PORT 5150
#define DATA_BUFSIZE 8192

typedef struct _SOCKET_INFORMATION {
OVERLAPPED Overlapped;
SOCKET Socket;
CHAR Buffer[DATA_BUFSIZE];
WSABUF DataBuf;
DWORD BytesSEND;
DWORD BytesRECV;
} SOCKET_INFORMATION, * LPSOCKET_INFORMATION;

void CALLBACK WorkerRoutine(DWORD Error, DWORD BytesTransferred,
LPWSAOVERLAPPED Overlapped, DWORD InFlags);

DWORD WINAPI WorkerThread(LPVOID lpParameter);

SOCKET AcceptSocket;

void main(void)
{
WSADATA wsaData;
SOCKET ListenSocket;
SOCKADDR_IN InternetAddr;
INT Ret;
HANDLE ThreadHandle;
DWORD ThreadId;
WSAEVENT AcceptEvent;

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

if ((ListenSocket = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0,
WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)
{
printf("Failed to get a socket %d\n", WSAGetLastError());
return;
}

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

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

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

if ((AcceptEvent = WSACreateEvent()) == WSA_INVALID_EVENT)
{
printf("WSACreateEvent() failed with error %d\n", WSAGetLastError());
return;
}

// Create a worker thread to service completed I/O requests.

if ((ThreadHandle = CreateThread(NULL, 0, WorkerThread, (LPVOID) AcceptEvent, 0, &ThreadId)) == NULL)
{
printf("CreateThread failed with error %d\n", GetLastError());
return;
}

while(TRUE)
{
AcceptSocket = accept(ListenSocket, NULL, NULL);

if (WSASetEvent(AcceptEvent) == FALSE)
{
printf("WSASetEvent failed with error %d\n", WSAGetLastError());
return;
}
}
}

DWORD WINAPI WorkerThread(LPVOID lpParameter)
{
DWORD Flags;
LPSOCKET_INFORMATION SocketInfo;
WSAEVENT EventArray[1];
DWORD Index;
DWORD RecvBytes;

// Save the accept event in the event array.

EventArray[0] = (WSAEVENT) lpParameter;

while(TRUE)
{
// Wait for accept() to signal an event and also process WorkerRoutine() returns.

while(TRUE)
{
Index = WSAWaitForMultipleEvents(1, EventArray, FALSE, WSA_INFINITE, TRUE);

if (Index == WSA_WAIT_FAILED)
{
printf("WSAWaitForMultipleEvents failed with error %d\n", WSAGetLastError());
return FALSE;
}

if (Index != WAIT_IO_COMPLETION)
{
// An accept() call event is ready - break the wait loop
break;
}
}

WSAResetEvent(EventArray[Index - WSA_WAIT_EVENT_0]);

// Create a socket information structure to associate with the accepted socket.

if ((SocketInfo = (LPSOCKET_INFORMATION) GlobalAlloc(GPTR,
sizeof(SOCKET_INFORMATION))) == NULL)
{
printf("GlobalAlloc() failed with error %d\n", GetLastError());
return FALSE;
}

// Fill in the details of our accepted socket.

SocketInfo->Socket = AcceptSocket;
ZeroMemory(&(SocketInfo->Overlapped), sizeof(WSAOVERLAPPED));
SocketInfo->BytesSEND = 0;
SocketInfo->BytesRECV = 0;
SocketInfo->DataBuf.len = DATA_BUFSIZE;
SocketInfo->DataBuf.buf = SocketInfo->Buffer;

Flags = 0;
if (WSARecv(SocketInfo->Socket, &(SocketInfo->DataBuf), 1, &RecvBytes, &Flags,
&(SocketInfo->Overlapped), WorkerRoutine) == SOCKET_ERROR)
{
if (WSAGetLastError() != WSA_IO_PENDING)
{
printf("WSARecv() failed with error %d\n", WSAGetLastError());
return FALSE;
}
}

printf("Socket %d connected\n", AcceptSocket);
}

return TRUE;
}

void CALLBACK WorkerRoutine(DWORD Error, DWORD BytesTransferred,
LPWSAOVERLAPPED Overlapped, DWORD InFlags)
{
DWORD SendBytes, RecvBytes;
DWORD Flags;

// Reference the WSAOVERLAPPED structure as a SOCKET_INFORMATION structure
LPSOCKET_INFORMATION SI = (LPSOCKET_INFORMATION) Overlapped;

if (Error != 0)
{
printf("I/O operation failed with error %d\n", Error);
}

if (BytesTransferred == 0)
{
printf("Closing socket %d\n", SI->Socket);
}

if (Error != 0 || BytesTransferred == 0)
{
closesocket(SI->Socket);
GlobalFree(SI);
return;
}

// Check to see if the BytesRECV field equals zero. If this is so, then
// this means a WSARecv call just completed so update the BytesRECV field
// with the BytesTransferred value from the completed WSARecv() call.

if (SI->BytesRECV == 0)
{
SI->BytesRECV = BytesTransferred;
SI->BytesSEND = 0;
}
else
{
SI->BytesSEND += BytesTransferred;
}

if (SI->BytesRECV > SI->BytesSEND)
{

// Post another WSASend() request.
// Since WSASend() is not gauranteed to send all of the bytes requested,
// continue posting WSASend() calls until all received bytes are sent.

ZeroMemory(&(SI->Overlapped), sizeof(WSAOVERLAPPED));

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

if (WSASend(SI->Socket, &(SI->DataBuf), 1, &SendBytes, 0,
&(SI->Overlapped), WorkerRoutine) == SOCKET_ERROR)
{
if (WSAGetLastError() != WSA_IO_PENDING)
{
printf("WSASend() failed with error %d\n", WSAGetLastError());
return;
}
}
}
else
{
SI->BytesRECV = 0;

// Now that there are no more bytes to send post another WSARecv() request.

Flags = 0;
ZeroMemory(&(SI->Overlapped), sizeof(WSAOVERLAPPED));

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

if (WSARecv(SI->Socket, &(SI->DataBuf), 1, &RecvBytes, &Flags,
&(SI->Overlapped), WorkerRoutine) == SOCKET_ERROR)
{
if (WSAGetLastError() != WSA_IO_PENDING )
{
printf("WSARecv() failed with error %d\n", WSAGetLastError());
return;
}
}
}
}
admireO 2001-04-28
  • 打赏
  • 举报
回复
能不能多来点代码.

16,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

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