Windows Sockets网络编程(4)套接字重叠IO模型

阅读: 评论:0

Windows Sockets网络编程(4)套接字重叠IO模型

Windows Sockets网络编程(4)套接字重叠IO模型

摘要:上一篇文章《Windows Sockets网络编程(3)WSAEventSelect模型开发》事件通知的Select模型,较之该文《Windows Sockets网络编程(1)TCP select & thread》中单纯的select模型有了很大的改进,其中一个最大的优点就是解决了Select不能被用户主动触发的问题。但是,还是存在不少缺陷。试想这样的情景:一般网络通信的这样的,①首先网卡收到数据,②然后Socket阻塞事件被触发,③接着开始读取网卡数据,④读取完毕开始使用相关数据。其中,将数据从网卡读取到内存中的操作,又称作IO操作。这种操作一般是耗时的。在学习《操作系统》课程中,学习过一种叫做“DMA的直接内存访问机制”,这种机制主要是将IO数据直接送往内存中某处,而基本不需要CPU干预,当IO操作完毕时再通知CPU。这是一个操作系统领域的突破性进展,极大的解放了CPU的工作强度。本文即将介绍的套接字重叠IO模型,是一种几乎不需要CPU参与,就能将数据从网卡输送到内存相应位置的技术,它主要有两种实现方式:事件通知和完成例程。

 

目录:

-----------------------------------------------

- 事件通知

    - WSARecv与LPWSAOVERLAPPED

    - 立即数据与异步问题

    - WSAGetOverlappedResult函数

    - 绑定SOCKET与EVENT

- 完成例程

    - 何为APC函数?

    - 完成例程的原型

    - 线程可警告状态SleepEx

- 实践1:事件通知模型

- 实践2:完成例程模型

- 实践3:TCPClient

 

1.事件通知

〇 WSARecv与LPWSAOVERLAPPED

事件通知技术的故事要从WSARecv函数说起,这里只关注事件通知是如何完成的,而不去关注其他细节。观察一下函数原型,

WSARecv(

_In_ SOCKETs,

_In_reads_(dwBufferCount)__out_data_source(NETWORK)LPWSABUFlpBuffers,

_In_ DWORDdwBufferCount,

_Out_opt_ LPDWORDlpNumberOfBytesRecvd,

_Inout_ LPDWORDlpFlags,

_Inout_opt_ LPWSAOVERLAPPED lpOverlapped,

_In_opt_ LPWSAOVERLAPPED_COMPLETION_ROUTINElpCompletionRoutine

);

从上述原型中可以看到倒数第二个参数LPWSAOVERLAPPED,这并不是一个系统变量类型,而是一个结构体,原型如下,

typedef struct _OVERLAPPED {ULONG_PTR Internal;ULONG_PTR InternalHigh;union {struct {DWORD Offset;DWORD OffsetHigh;} DUMMYSTRUCTNAME;PVOID Pointer;} DUMMYUNIONNAME;HANDLE hEvent;
} OVERLAPPED, *LPOVERLAPPED;

同样,这里只关注与事件相关的最重要的参数HANDLE hEvent。文章讲到这里,基本上已经梳理清楚了事件通知模型的条理了——就是WSACreateEvent创建一个事件,将其绑定在结构体中的hEvent当中,然后将结构体整体作为WSARecv的一个参数。这样,当“网卡数据传输到内存指定位置时”,hEvent事件就会被激发(又叫做已触发状态),这时候直接去读取内存数据就可以了。

 

〇 立即数据与异步问题

那么,问题来了。WSARecv是非阻塞函数,数据要如何读取呢?

那么要继续分析一下这个函数,①非阻塞函数也是可以返回读取到的网卡数据的。②如果一时间获取不到网卡数据该怎么办?

针对问题1:WSARecv函数直接获取网卡数据。

这个毫无疑问,需要获取的数据量极其小,能在WSARecv被调用的一瞬间完成。那么,此时WSARecv函数返回值将为0,同时参数lpNumberOfBytesRecvd将被置为获取到的字节数。

针对问题2:一时间获取不到网卡数据。

WSARecv函数为非阻塞函数,它不会傻傻的等待网卡数据运输到内存。这时候,WSARecv函数会返回SOCKET_ERROR,一旦检测到该返回值,应该马上调用WSAGetLastError()获取此时的错误码——ERROR_IO_PENDING(一般是这个错误码,它表示recv操作正在异步执行中)。至于何时获取完毕?这就是上文说道的Event机制了。

 

BOOL EventNotification::recvAsynData()
{DWORD recv_length = 0L, flag = 0L;ZeroMemory(&m_io, sizeof(m_io));m_op_type = RECV_FLAG;m_io.hEvent = m_

本文发布于:2024-02-01 01:42:42,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170672296032943.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:网络编程   模型   Windows   Sockets   IO
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23