重叠I/O模型中使用事件通知方法的话,看看下面的源代码中的第五步吧。
由于使用重叠I/O模型,所以发送与接收函数中需要使用重叠结构,重叠结构中一个
事件成员,用于I/O操作的通知消息。
//=============================================================
// 重叠模型------事件对象通知
// 重叠模型的基本设计原理便是让应用程序使用重叠的数据结构,一次
//投递一个或多个Winsock I/O请求,针对这些提交的请求,在它们完成之后,
//应用程序可为它们提供服务。该模型适用于除Windows CE之外的各种Windows
//平台。
//
// 1.事件通知
// 重叠I/O的事件通知方法要求将Windows事件对象与WSAOVERLAPPED结构
//关联在一起。若使用一个WSAOVERLAPPED结构,发出像WSASend和WSARecv这
//样的I/O调用,它们会立即返回。(参考程序如下)
//
// 2.参考程序的扩展问题
// 这个程序极易扩展,从而提供对多个套接字的支持。方法是将代码中的
//重叠I/O处理部分移至一个独立的线程中,让主应用程序为额外的连接请求
//提供服务。
//=============================================================
#include <stdio.h>
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")
#define DATA_BUFSIZE 256
void main()
{
WSADATA Wsd;
WSABUF DataBuf;
char Buffer[DATA_BUFSIZE];
DWORD EventTotal = 0,
RecvBytes = 0,
Flags = 0,
BytesTransferred;
WSAEVENT EventArray[WSA_MAXIMUM_WAIT_EVENTS];
WSAOVERLAPPED AcceptOverlapped;
SOCKET ListenSocket, AcceptSocket;
SOCKADDR_IN InternetAddr, ClientAddr;
int saRemoteLen;
//第1步
//启动Winsock,建立监听套接字
WSAStartup(MAKEWORD(2, 2), &Wsd);
ListenSocket = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
InternetAddr.sin_family = AF_INET;
InternetAddr.sin_addr.s_addr = inet_addr("127.0.0.1");//htonl(INADDR_ANY);
InternetAddr.sin_port = htons(5150);
bind(ListenSocket, (SOCKADDR*)&InternetAddr, sizeof(InternetAddr));
listen(ListenSocket, 5);
//第2步
//接受一个入站连接
saRemoteLen = sizeof(ClientAddr);
AcceptSocket = WSAAccept(ListenSocket, (SOCKADDR*)&ClientAddr, &saRemoteLen, 0, NULL);
printf("Socket %d connected /n", AcceptSocket);
//第3步
//建立一个重叠结构
EventArray[EventTotal] = WSACreateEvent();
ZeroMemory(&AcceptOverlapped, sizeof(WSAOVERLAPPED));
AcceptOverlapped.hEvent = EventArray[EventTotal];
DataBuf.len = DATA_BUFSIZE;
DataBuf.buf = Buffer;
EventTotal++;
//第4步
//投递一个WSARecv请求,以便开始在套接字上接收数据
if (WSARecv(AcceptSocket, &DataBuf, 1, &RecvBytes, &Flags, &AcceptOverlapped, NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() != WSA_IO_PENDING)
{
//出错
}
}
//处理套接字上的重叠接收
while (TRUE)
{
DWORD Index;
//第5步
//等候重叠I/O调用结束
Index = WSAWaitForMultipleEvents(EventTotal, EventArray, FALSE, WSA_INFINITE, FALSE);
//索引应为0,因为EventArray中仅有一个事件
//第6步
//重置已传信事件
WSAResetEvent(EventArray[Index - WSA_WAIT_EVENT_0]);
//第7步
//确定重叠请求的状态
WSAGetOverlappedResult(AcceptSocket, &AcceptOverlapped, &BytesTransferred, FALSE, &Flags);
//先检查看通信对方是否已关闭连接,如果已经关闭,则关闭套接字
if (BytesTransferred == 0)
{
printf("Closing socket %d /n", AcceptSocket);
closesocket(AcceptSocket);
WSACloseEvent(EventArray[Index - WSA_WAIT_EVENT_0]);
return;
}
//对接收到的数据进行某种处理
//DataBuf包含接收到的数据
//......
printf("Receive data from %d !/n", AcceptSocket);
//第8步
//在套接字上投递另一个WSARecv()请求
Flags = 0;
ZeroMemory(&AcceptOverlapped, sizeof(WSAOVERLAPPED));
AcceptOverlapped.hEvent = EventArray[Index - WSA_WAIT_EVENT_0];
DataBuf.len = DATA_BUFSIZE;
DataBuf.buf = Buffer;
if (WSARecv(AcceptSocket, &DataBuf, 1, &RecvBytes, &Flags, &AcceptOverlapped, NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() != WSA_IO_PENDING)
{
//未预料到的错误
}
}
}
WSACleanup();
}
__________________
wetwood->wetwoo