WinSock IO模型---重叠模型

本文详细介绍如何使用Winsock的重叠IO技术提高应用程序性能。包括创建套接字、接收请求、处理重叠IO操作等步骤,并附带示例代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

重叠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 4096

int _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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值