使用异步套接字模式进行Windows网络编程

文章转摘自互联网。

使用异步套接字模式进行Windows网络编程
上面我们使用多线程技术解决了阻塞套接字模式的阻塞问题。微软提供了另外一种不使用多线程技术解决阻塞问题的方法,即异步套接字模式。
所谓异步套接字,是指基于消息的、非阻塞模式的套接字。
Windows套接字可以在两种模式下执行I/O操作,即阻塞模式和非阻塞模式。
在阻塞模式下,在I/O操作完成前,执行操作的Winsock函数会一直等待下去,不会立即返回程序(即不会将控制权立即交还给程序)。而在非阻塞模式下,Winsock函数无论如何都会立即返回。
Windows Sockets为了支持Windows消息驱动机制,使应用程序开发者能够方便地处理网络通信,它对网络事件采用了基于消息的异步存取策略。该异步策略主要是通过Windows Sockets的异步选择函数WSAAsyncSelect()来实现的,该函数提供了消息机制的网络事件选择,当使用它登记的网络事件发生时,Windows应用程序相应的窗口函数将收到一个消息,消息中指示了发生的网络事件,以及与事件相关的一些信息。
在缺省情况下,Berkerley的Socket函数和WinSock都创建“阻塞”的socket。我们可以通过使用select函数或者WSAAsynSelect函数使原本阻塞的socket变成非阻塞的。这些非阻塞函数一般是在原阻塞函数名前加上WSA前缀而形成的。如:
socketWSAAsyncSocket
recvfromWSARecvFrom
sendtoWSASendto
WSAAsyncSelect函数原型如下。
int WSAAsyncSelect(
SOCKET  s,
HWND  hWnd,
u_int  wMsg,
long   lEvent
);
其中,参数s指定了要操作的socket句柄;参数 hWnd指定了一个窗口句柄;参数 wMsg指定了一个消息,参数lEvent指定了网络事件,可以是多个事件的组合,如:
FD_READ 准备读
FD_WRITE 准备写
FD_OOB 带外数据到达
FD_ACCEPT 收到连接
FD_CONNECT 完成连接
FD_CLOSE 关闭socket。
可以用OR操作(|)来组合这些事件,如FD_READ | FD_WRITE
WSAAsyncSelect函数表示对socket s监测lEvent指定的网络事件,如果有事件发生,则给窗口hWnd发送消息wMsg。
假定应用程序的一个socket s指定了监测FD_READ事件,则在FD_READ事件上变成非阻塞的。当read函数被调用时,不管是否读到数据都马上返回,如果返回一个错误信息表示还在等待;而在等待的数据到达后,就会发送消息wMsg给窗口hWnd,应用程序处理该消息读取网络数据。

启动一个WSAAsyncSelect()将使为同一个套接字启动的所有先前的WSAAsyncSelect()作废。例如,要接收读写通知,应用程序必须同时用FD_READ和FD_WRITE调用WSAAsyncSelect(),如下:
WSAAsyncSelect(s, hWnd, wMsg, FD_READ|FD_WRITE);
对不同的事件区分不同的消息是不可能的,下面的代码将不会工作;第二次调用将会使第一次调用失效,只有FD_WRITE会通过wMsg2消息通知到。
WSAAsyncSelect(s, hWnd, wMsg1, FD_READ);
WSAAsyncSelect(s, hWnd, wMsg2, FD_WRITE);

如果要取消所有的通知,也就是指出Windows Sockets的实现不再需要在套接字上发送任何和网络事件相关的消息,则lEvent应置为0:
WSAAsyncSelect(s, hWnd, 0, 0);

相关函数说明

SOCKET WSASocket(
int       af,
int       type,
int       protocol,
LPWSAPROTOCOL_INFO  lpProtocolInfo,
GROUP      g,
DWORD      dwFlags
);

前三个参数和socket()函数的前三个参数含义一样。
lpProtocolInfo,一个指向WSAPROTOCOL_INFO结构体的指针,该结构定义了所创建的套接字的特性。如果lpProtocolInfo为NULL,则WinSock2 DLL使用前三个参数来决定使用哪一个服务提供者,它选择能够支持规定的地址族、套接字类型和协议值的第一个传输提供者。如果lpProtocolInfo不为NULL,则套接字绑定到与指定的结构WSAPROTOCOL_INFO相关的提供者。
g,保留的。
dwFlags,套接字属性的描述。
int WSARecvFrom(
SOCKET           s,
LPWSABUF          lpBuffers,
DWORD           dwBufferCount,
LPDWORD          lpNumberOfBytesRecvd,
LPDWORD          lpFlags,
struct sockaddr FAR        *lpFrom,
LPINT           lpFromlen,
LPWSAOVERLAPPED        lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE  lpCompletionRoutine
);
s,标识套接字的描述符。
lpBuffers,[in, out],一个指向WSABUF结构体的指针。每一个WSABUF结构体包含一个缓冲区的指针和缓冲区的长度。
dwBufferCount, lpBuffers数组中WSABUF结构体的数目。
lpNumberOfBytesRecvd,[out],如果接收操作立即完成,则为一个指向本次调用所接收的字节数的指针。
lpFlags,[in, out],一个指向标志位的指针。
lpFrom,[out],可选指针,指向重叠操作完成后存放源地址的缓冲区。
lpFromlen,[in, out],指向from缓冲区大小的指针,仅当指定了lpFrom才需要。
lpOverlapped,一个指向WSAOVERLAPPED结构体的指针(对于非重叠套接字则忽略)。
lpCompletionRoutine,一个指向接收操作完成时调用的完成例程的指针(对于非重叠套接字则忽略)。int WSASendTo(

SOCKET          s,
LPWSABUF          lpBuffers,
DWORD           dwBufferCount,
LPDWORD          lpNumberOfBytesSent,
DWORD           dwFlags,
const struct sockaddr FAR       *lpTo,
int            iToLen,
LPWSAOVERLAPPED        pOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE  CompletionRoutine
);
s,标识一个套接字(可能已连接)的描述符。
lpBuffers,一个指向WSABUF结构体的指针。每一个WSABUF结构体包含一个缓冲区的指针和缓冲区的长度。
dwBufferCount, lpBuffers数组中WSABUF结构体的数目。
lpNumberOfBytesSent,[out],如果发送操作立即完成,则为一个指向本次调用所发送的字节数的指针。
dwFlags,指示影响操作行为的标志位。
lpTo,可选指针,指向目标套接字的地址。
iToLen,lpTo中地址的长度。
lpOverlapped,一个指向WSAOVERLAPPED结构的指针(对于非重叠套接字则忽略)。
lpCompletionRoutine,一个指向接收操作完成时调用的完成例程的指针(对于非重叠套接字则忽略)。

 

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页