WinSock IO模型---重叠模型

来源:互联网 发布:linux 防火墙 firewall 编辑:程序博客网 时间:2024/04/19 09:34

重叠IO(overlapped IO)是可以是应用程序达到好的系统性能;

设计的原理便是:让应用程序使用一个重叠的数据结构,一次投递一个或者多个IO请求。

1.创建一个套接字,并在指定的端口上监听。

使用下面的函数,并设置WSA_FLAG_OVERLAPPED这个标志创建套接字,创建套接字时候假如使用的是socket则默认设置好了该标志。
s=WSASocket(AF_INET,SOCK_STREAM,0,WSA_FLAG_OVERLAPPED);

2.创建成功以后,将其与本地的接口绑定到一起,便可以进行重叠的IO操作。

3.接收一个进入的请求。

4.为接受的套接字新建一个WSAOVERLAPPED结构,并为该结构分配一个事件对象句柄,把该句柄分配一个事件数组,以便稍后在WSAWaitForMultipleEvents中使用。

结构体的说明:

typedef struct _WSAOVERLAPPED 
{  ULONG_PTR Internal;  
   ULONG_PTR InternalHigh;  
   union 
   {  
  struct
  {    
  DWORD Offset;     
  DWORD OffsetHigh;  //前4个参数有系统内部使用,程序不直接使用处理 
  };     
  PVOID Pointer; 
   }; 
   HANDLE hEvent;//允许将一个套接字和和事件关联在一起;
} WSAOVERLAPPED,  *LPWSAOVERLAPPED;

5.在套接字上投递一个异步的WSARecv请求,指定参数WSAOVERLAPPED结构。

注:函数通常会失败,返回SOCKET_ERROR状态WSA_IO_PENGING(io操作未完成);

6.使用4中的事件数组,调用WSAWaitForMultipleEvents等待与重叠关联事件变成传信状态。

说明:一个重叠请求操作最终完成之后,在事件的通知方法中,winsock会把WSAOVERLAPPED结构中的事件由未传信状态变为已传信状态;事件已经分配给了WSAOVERLAPPED所以只需要简单的调用WSAWaitForEvents就可以判断出一个IO调用在什么时候完成。

7.WSAWaitForMultipleEvent函数完成后,针对事件数组,调用WSAResetEvent重设事件对象,并对完成的重叠请求进行处理;

8.使用WSAGetOverlappedResult函数,判断重叠调用的返回状态是什么。

说明:发现一次重叠请求完成之后,需要调用WSAGetOverlappedResult(获得重叠结构)函数,来判断那个重叠请
求到底是成功,还是失败。
BOOL WSAGetOverlappedResult

(

   IN SOCKET s, //重叠操作开始时,与之对应的套接字

  IN LPWSAOVERLAPPED lpOverlapped, //WSAOVERLAPPED

  OUT LPDWORD lpcbTransfer, //负责接收一次重叠发送或者接收实际传输的字节
  IN BOOL fWait,  //确定函数是否应该等待一次未完成的重叠操作完成;TRUE表示一直等到操作完成再返回;
  OUT LPDWORD lpdwFlags  //负责接收结果标志   
  )
返回值的分析:该函数成功返回的TRUE,表示我们的重叠IO已经完成。而且lpcbTransfer函数指向的值已经得到更新,如果返回的是FALSE则可能是一下的原因:1.重叠的IO仍然在待决的状态。
                                                                            2.重叠IO完成,但是有错误。
                                                                            3.重叠IO的完成状态不可以判断,因为传递给该函数的一个或者多个参数存在错误;

9.在套接字上投递里另外一个重叠WSARecv请求。

10.重复6--9;

示例代码:

#include "stdafx.h"#include <stdio.h>#include <WinSock2.h>#include <Windows.h>#pragma comment(lib,"ws2_32.lib")#define  PORT 5150#define  DATA_BUFFER 4096int _tmain(int argc, _TCHAR* argv[]){WSADATA WSAdata;SOCKET  sListen,sAccept;WSAEVENT EventArray[WSA_MAXIMUM_WAIT_EVENTS];WSAOVERLAPPED overlapped;DWORD EventTotal=0;DWORD byteRecv=0;DWORD Flags=0;DWORD ByteTranfer=0;WSABUF wsabuf;char   buffer[DATA_BUFFER];if ((WSAStartup(MAKEWORD(2,2),&WSAdata))!=0){printf("WSAStartup() Failed with error %d",WSAGetLastError());return 0;}    sListen=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);if (sListen==INVALID_SOCKET){printf("socket() Failed with error %d",WSAGetLastError());return 0;}    SOCKADDR_IN listenAddr;listenAddr.sin_addr.S_un.S_addr=htonl(INADDR_ANY);listenAddr.sin_family=AF_INET;listenAddr.sin_port=htons(PORT);if (bind(sListen, (PSOCKADDR)&listenAddr, sizeof(listenAddr)) == SOCKET_ERROR){printf("bind() failed with error %d\n", WSAGetLastError());return 0;}if (listen(sListen, 5)){printf("listen() failed with error %d\n", WSAGetLastError());return 0;}printf("Listening...\n");    sAccept=accept(sListen,NULL,NULL);if (sListen==INVALID_SOCKET){printf("accept() Failed with error %d",WSAGetLastError());return 0;}EventArray[EventTotal]=WSACreateEvent();ZeroMemory(&overlapped,sizeof(overlapped));overlapped.hEvent=EventArray[EventTotal];EventTotal++;    wsabuf.buf=buffer;wsabuf.len=DATA_BUFFER;if ((WSARecv(sAccept,&wsabuf,1,&byteRecv,&Flags,&overlapped,NULL))==SOCKET_ERROR){if (WSAGetLastError()!=WSA_IO_PENDING){printf("Error occurred at WSARecv()\n");return 0;}}while(TRUE){DWORD index;index=WSAWaitForMultipleEvents(EventTotal,EventArray,FALSE,WSA_INFINITE,FALSE);WSAResetEvent(EventArray[index - WSA_WAIT_EVENT_0]);WSAGetOverlappedResult(sAccept, &overlapped,&ByteTranfer, FALSE, &Flags);        //if the connection close,if so closesocket;if (ByteTranfer==0){printf("Closing Socket %d\n", sAccept);closesocket(sAccept);WSACloseEvent(EventArray[index - WSA_WAIT_EVENT_0]);return 0;}if (WSASend(sAccept, &wsabuf, 1, &byteRecv, Flags, &overlapped, NULL) == SOCKET_ERROR){           printf("WSASend() is busted\n");}//post another WSARecv on socket;Flags=0;ZeroMemory(&overlapped,sizeof(overlapped));overlapped.hEvent=EventArray[index-WSA_WAIT_EVENT_0];wsabuf.buf=buffer;wsabuf.len=DATA_BUFFER;if ((WSARecv(sAccept,&wsabuf,1,&byteRecv,&Flags,&overlapped,NULL))==SOCKET_ERROR){if (WSAGetLastError()!=WSA_IO_PENDING){printf("Error occurred at WSARecv()\n");return 0;}}}return 0;}


原创粉丝点击