Winsock 2 I/O Methods 5 Part 11

2023-11-01

Winsock 2 I/O Methods 5 Part 11

 

 

What do we have in this chapter 5 part 11?

  1. Testing the Client-server Program

  2. Completion Ports and Overlapped I/O

  3. Per-handle Data and Per-I/O Operation Data

  4. I/O Model Consideration

  5. Client Development

  6. Server Development

 

 

Testing the Client-server Program

 

Firstly we run the server program.

 

The Completion Port Model: program example tries to demonstrate the server/receiver that implements completion port model. Running the client-server programs. Server/receiver is waiting connection

 

Then we run the client program.

 

The Completion Port Model: program example tries to demonstrate the server/receiver that implements completion port model. running the client program

 

The error code 10054 (WSAECONNRESET) means the connection was reset by peer (in this case the server). The previous server sample output when communication was completed is shown below.

 

The Completion Port Model: program example tries to demonstrate the server/receiver that implements completion port model. The server/receiver sample output when communication was completed

 

Completion Ports and Overlapped I/O

 

After associating a socket handle with a completion port, you can begin processing I/O requests by posting overlapped send and receive requests on the socket handle. You can now start to rely on the completion port for I/O completion notification. Basically, the completion port model takes advantage of the Windows overlapped I/O mechanism in which Winsock API calls such as WSASend() and WSARecv() return immediately when called. It is up to your application to retrieve the results of the calls at a later time through an OVERLAPPED structure. In the completion port model, this is accomplished by having one or more worker threads wait on the completion port using the GetQueuedCompletionStatus() function, which is defined as:

 

BOOL GetQueuedCompletionStatus(

    HANDLE CompletionPort,

    LPDWORD lpNumberOfBytesTransferred,

    PULONG_PTR lpCompletionKey,

    LPOVERLAPPED * lpOverlapped,

    DWORD dwMilliseconds

);

 

The CompletionPort parameter represents the completion port to wait on. The lpNumberOfBytesTransferred parameter receives the number of bytes transferred after a completed I/O operation, such as WSASend() or WSARecv(). The lpCompletionKey parameter returns per-handle data for the socket that was originally passed into the CreateIoCompletionPort() function. As we already mentioned, we recommend saving the socket handle in this key. The lpOverlapped parameter receives the WSAOVERLAPPED structure of the completed I/O operation. This is actually an important parameter because it can be used to retrieve per I/O-operation data, which we will describe shortly. The final parameter, dwMilliseconds, specifies the number of milliseconds that the caller is willing to wait for a completion packet to appear on the completion port. If you specify INFINITE, the call waits forever.

 

Per-handle Data and Per-I/O Operation Data

 

When a worker thread receives I/O completion notification from the GetQueuedCompletionStatus() API call, the lpCompletionKey and lpOverlapped parameters contain socket information that can be used to continue processing I/O on a socket through the completion port. Two types of important socket data are available through these parameters: per-handle data and per-I/O operation data.

The lpCompletionKey parameter contains what we call per-handle data because the data is related to a socket handle when a socket is first associated with the completion port. This is the data that is passed as the CompletionKey parameter of the CreateIoCompletionPort() API call. As we noted earlier, your application can pass any type of socket information through this parameter. Typically, applications will store the socket handle related to the I/O request here.

The lpOverlapped parameter contains an OVERLAPPED structure followed by what we call per-I/O operation data, which is anything that your worker thread will need to know when processing a completion packet (echo the data back, accept the connection, post another read, and so on). Per-I/O operation data is any number of bytes contained in a structure also containing an OVERLAPPED structure that you pass into a function that expects an OVERLAPPED structure. A simple way to make this work is to define a structure and place an OVERLAPPED structure as a field of the new structure. For example, we declare the following data structure to manage per-I/O operation data:

 

typedefstruct

{

    OVERLAPPED Overlapped;

   char       Buffer[DATA_BUFSIZE];

   int    BufferLen;

   int        OperationType;

} PER_IO_DATA;

 

This structure demonstrates some important data elements you might want to relate to an I/O operation, such as the type of I/O operation (a send or receive request) that just completed. In this structure, we consider the data buffer for the completed I/O operation to be useful. To call a Winsock API function that expects an OVERLAPPED structure, you dereference the OVERLAPPED element of your structure. For example:

 

PER_IO_OPERATION_DATA PerIoData;

WSABUF wbuf;

DWORD Bytes, Flags;

 

// Initialize wbuf ...

WSARecv(socket, &wbuf, 1, &Bytes, &Flags, &(PerIoData.Overlapped), NULL);

 

Later in the worker thread, GetQueuedCompletionStatus() returns with an overlapped structure and completion key. To retrieve the per-I/O data the macro CONTAINING_RECORD should be used. For example,

 

PER_IO_DATA  *PerIoData=NULL;

OVERLAPPED   *lpOverlapped=NULL;

 

ret = GetQueuedCompletionStatus(

         CompPortHandle,

         &Transferred,

         (PULONG_PTR)&CompletionKey,

         &lpOverlapped,            INFINITE);

 

// Check for successful return

PerIoData = CONTAINING_RECORD(lpOverlapped, PER_IO_DATA, Overlapped);

 

This macro should be used; otherwise, the OVERLAPPED member of the PER_IO_DATA structure would always have to appear first, which can be a dangerous assumption to make (especially with multiple developers working on the same code).

You can determine which operation was posted on this handle by using a field of the per-I/O structure to indicate the type of operation posted. In our example, the OperationType member would be set to indicate a read, write, etc., operation. One of the biggest benefits of per-I/O operation data is that it allows you to manage multiple I/O operations (such as read/write, multiple reads, and multiple writes) on the same handle. You might ask why you would want to post more than one I/O operation at a time on a socket. The answer is scalability. For example, if you have a multiple-processor machine with a worker thread using each processor, you could potentially have several processors sending and receiving data on a socket at the same time.

Before continuing, there is one other important aspect about Windows completion ports that needs to be stressed. All overlapped operations are guaranteed to be executed in the order that the application issued them. However, the completion notifications returned from a completion port are not guaranteed to be in that same order. That is, if an application posts two overlapped WSARecv() operations, one with a 10 KB buffer and the next with a 12 KB buffer, the 10 KB buffer is filled first, followed by the 12 KB buffer. The application's worker thread may receive notification from GetQueuedCompletionStatus() for the 12 KB WSARecv() before the completion event for the 10 KB operation. Of course, this is only an issue when multiple operations are posted on a socket. To complete this simple echo server sample, we need to supply a ServerWorkerThread() function. The following code outlines how to develop a worker thread routine that uses per-handle data and per-I/O operation data to service I/O requests.

 

 DWORD WINAPI ServerWorkerThread(LPVOID CompletionPortID)

{

    HANDLE CompletionPort = (HANDLE) CompletionPortID;

    DWORD BytesTransferred;

    LPOVERLAPPED Overlapped;

    LPPER_HANDLE_DATA PerHandleData;

    LPPER_IO_DATA PerIoData;

    DWORD SendBytes, RecvBytes;

    DWORD Flags;

 

   while(TRUE)

    {

       // Wait for I/O to complete on any socket

       // associated with the completion port   

        ret = GetQueuedCompletionStatus(CompletionPort, &BytesTransferred,(LPDWORD)&PerHandleData,

            (LPOVERLAPPED *) &PerIoData, INFINITE);

 

       // First check to see if an error has occurred

       // on the socket; if so, close the

       // socket and clean up the per-handle data

       // and per-I/O operation data associated with the socket

       if (BytesTransferred == 0 && (PerIoData->OperationType == RECV_POSTED ││ PerIoData->OperationType == SEND_POSTED))

        {

           // A zero BytesTransferred indicates that the

           // socket has been closed by the peer, so

           // you should close the socket. Note:

           // Per-handle data was used to reference the

           // socket associated with the I/O operation.

            closesocket(PerHandleData->Socket);

 

            GlobalFree(PerHandleData);

            GlobalFree(PerIoData);

           continue;

        }

 

 

       // Service the completed I/O request. You can

       // determine which I/O request has just

       // completed by looking at the OperationType

       // field contained in the per-I/O operation data.

        if (PerIoData->OperationType == RECV_POSTED)

        {

           // Do something with the received data in PerIoData->Buffer

        }

       // Post another WSASend or WSARecv operation.

       // As an example, we will post another WSARecv() I/O operation.

        Flags = 0;

       // Set up the per-I/O operation data for the next overlapped call

        ZeroMemory(&(PerIoData->Overlapped), sizeof(OVERLAPPED));

        PerIoData->DataBuf.len = DATA_BUFSIZE;

        PerIoData->DataBuf.buf = PerIoData->Buffer;

        PerIoData->OperationType = RECV_POSTED;

        WSARecv(PerHandleData->Socket, &(PerIoData->DataBuf), 1, &RecvBytes, &Flags, &(PerIoData->Overlapped), NULL);

    }

}

 

If an error has occurred for a given overlapped operation, GetQueuedCompletionStatus() will return FALSE. Because completion ports are a Windows I/O construct, if you call GetLastError() or WSAGetLastError(), the error code is likely to be a Windows error code and not a Winsock error code. To retrieve the equivalent Winsock error code, WSAGetOverlappedResult() can be called specifying the socket handle and WSAOVERLAPPED structure for the completed operation, after which WSAGetLastError() will return the translated Winsock error code.

One final detail not outlined in the last two examples we have presented is how to properly close an I/O completion port especially if you have one or more threads in progress performing I/O on several sockets. The main thing to avoid is freeing an OVERLAPPED structure when an overlapped I/O operation is in progress. The best way to prevent this is to call closesocket() on every socket handle any overlapped I/O operations pending will complete. Once all socket handles are closed, you need to terminate all worker threads on the completion port. This can be accomplished by sending a special completion packet to each worker thread using the PostQueuedCompletionStatus() function, which informs each thread to exit immediately. PostQueuedCompletionStatus() is defined as:

 

BOOL PostQueuedCompletionStatus(

    HANDLE CompletionPort,

    DWORD dwNumberOfBytesTransferred,

    ULONG_PTR dwCompletionKey,

    LPOVERLAPPED lpOverlapped

);

 

The CompletionPort parameter represents the completion port object to which you want to send a completion packet. The dwNumberOfBytesTransferred, dwCompletionKey, and lpOverlapped parameters each will allow you to specify a value that will be sent directly to the corresponding parameter of the GetQueuedCompletionStatus() function. Thus, when a worker thread receives the three passed parameters of GetQueuedCompletionStatus(), it can determine when it should exit based on a special value set in one of the three parameters. For example, you could pass the value 0 in the dwCompletionKey parameter, which a worker thread could interpret as an instruction to terminate. Once all the worker threads are closed, you can close the completion port using the CloseHandle() function and finally exit your program safely.

The completion port I/O model is by far the best in terms of performance and scalability. There are no limitations to the number of sockets that may be associated with a completion port and only a small number of threads are required to service the completed I/O.

 

I/O Model Consideration

 

By now you might be wondering how to choose the I/O model you should use when designing your application. As we've mentioned, each model has its strengths and weaknesses. All of the I/O models do require fairly complex programming compared with developing a simple blocking-mode application with many servicing threads. We offer the following suggestions for client and server development.

 

Client Development

 

When you are developing a client application that manages one or more sockets, we recommend using overlapped I/O or WSAEventSelect() over the other I/O models for performance reasons. But, if you are developing a Windows-based application that manages window messages, the WSAAsyncSelect model might be a better choice because WSAAsyncSelect() lends itself to the Windows message model, and your application is already set up for handling messages.

 

Server Development

 

When you are developing a server that processes several sockets at a given time, we recommend using overlapped I/O over the other I/O models for performance reasons. However, if you expect your server to service a large number of I/O requests at any given time, you should consider using the I/O completion port model for even better performance.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Winsock 2 I/O Methods 5 Part 11 的相关文章

  • VOS论文阅读:Fast Video Object Segmentation using the Global Context Module(2020 ECCV)

    Fast Video Object Segmentation using the Global Context Module 2020 ECCV Contribution Method Global Context Module Conte
  • redis 数据类型之字符串(string) 详细介绍

    字符串 string 键是Redis最基本的键值对类型 这种类型的键值对会在数据库中把单独的一个键和单独的一个值关联起来 被关联的键和值既可以是普通的文字数据 也可以是图片 视频 音频 压缩文件等更为复杂的二进制数据 图2 1展示了数据库视
  • openwrt 完美安装 tcpdump

    直接使用 opk install tcpdump 报下面的错 Collected errors check data file clashes Package libpcap1 wants to install file usr lib l
  • Makeflow用户手册 一

    Makeflow用户手册 概述 Makeflow是用于大规模分布式计算的工作流引擎 它接受要执行的大量工作的规范 并尽可能在远程计算机上并行运行 此外 Makeflow是容错的 因此您可以使用它来协调非常大的任务 这些任务可能在出现故障时运
  • (4)各个属性角色分析显示-4

    将折线图 数据集 散点图集合在一个html文件中 1 将折线图 数据集 散点图设置为函数a b c 2 再调用page add 函数 将三个图片组合在一起 3 运行page render x html 函数 将该页面命名 打开html文件
  • Java线程中处理运行时异常(UncaughtExceptionHandler)

    线程在执行单元中不允许抛出checked异常 而且线程运行在自己的上下文中 派生它的线程无法直接获得它运行中出现的异常信息 对此 Java为我们提供了UncaughtExceptionHandler接口 当线程在运行过程中出现异常时 会回调
  • ElasticSearch多字段查询best_fields、most_fields和cross_fields理解

    基于elasticsearch7 6 1 和 kibana7 6 1 本文通过案例进行讲解 希望读者耐心阅读 一 介绍 字段中心查询式 就是以字段为中心 代表就是 best fields和most fields 把所有的字段全都散列 然后从

随机推荐

  • 详解曼哈顿距离&欧式距离&切比雪夫距离

    详解曼哈顿 欧式距离 切比雪夫距离 曼哈顿距离 基本概念 出租车几何或曼哈顿距离 Manhattan Distance 是由十九世纪的赫尔曼 闵可夫斯基所创词汇 是种使用在几何度量空间的几何学用语 用以标明两个点在标准坐标系上的绝对轴距总和
  • 基于32单片机的16通道ADC的数据采集

    基于32单片机的16通道ADC的数据采集 这个部分的内容 是作为外部模拟量部分的采集工作 按照任务要求 所设计的方案 需要完成以下指标 ADC必须能采集16通道的模拟量 ADC的分辨率是16bit 采样率不小于20khz 由此分析可以得出
  • 请使用正确的入口登录面板—解决方案

    错误信息提示 解决方案 一 找回安全登录地址 宝塔登录地址 http 你的服务器ip 8888 但是这种格式是不安全的 目前新安装的宝塔面板默认都开启了安全目录登录 所以如果使用这种不带有8位字符随机码的登录地址就会提示 请使用正确的入口登
  • 【AI】《动手学-深度学习-PyTorch版》笔记(二十一):目标检测

    AI学习目录汇总 1 简述 通过前面的学习 已经了解了图像分类模型的原理及实现 图像分类是假定图像中只有一个目标 算法上是对整个图像做的分类 下面我们来学习 目标检测 即从一张图像中找出需要的目标 并标记出位置 2 边界框 边界框 boun
  • xctf攻防世界—Web新手练习区robots单题思路

    xctf攻防世界 Web新手练习区robots单题思路 邱邱邱自强 前言 随着互联网的发展 互联网界的行为也越来越被重视 那么国际互联网界通行的道德规范是什么呢 它就是Robots协议 一 Robots协议是什么 robots协议也叫rob
  • 点击Path环境变量编辑不展开的问题

    分析 将 MYSQL HOME bin移动到 JAVA HOME bin的上面 点击确定 再次点击Path环境变量就会出现编辑不展开的问题 如图所示 分析原因 因为我把两个 MYSQL HOME bin和 JAVA HOME bin一起放在
  • zip、unzip命令使用

    1 zip压缩命令 1 压缩文件 zip test test txt 将text txt文件压缩到test zip文件中 2 压缩文件夹 r zip r attack zip attack 将当前路径下attack文件夹中的文件进行压缩 压
  • assert在debug 和 release版本中的区别

    转自 https blog csdn net panfengsoftware article details 8910468 debug版本与release的不同点 debug版本中含有调试信息 不会对程序进行优化 assert相应的宏会被
  • python-一些坑点

    一些python使用中遇到的坑点 记录一下 同样的问题也可能只是对当前我的环境下有作用 AttributeError module urllib has no attribute splittype 使用urllib中的一些工具时 提示这个
  • FPGA中task语法基本使用

    1 task定义为任务 完成的是某个具体功能 可以在initial语句和always语句中使用 不过initial语句使用较多 2 task如何使用 1 定义任务 task 任务名 端口及数据类型声明语句 语句1 语句2 语句n endta
  • Qt 3D的研究(三):显示3D模型

    Qt 3D的研究 三 显示3D模型 上一篇文章介绍了如何使用最少的代码创建一个Qt 3D的应用 和大家最初接触的glut一样 对于3D应用来说 需要做的准备工作还真不少 不过呢 Qt 3D把一些窗口相关的琐碎事情解决了 剩下的 该由我们完成
  • 修复nanopi2的SPI无法使用50MHZ传输的问题(S5P4418)

    关于S5P4418使用SPI DMA传输时出现的超时问题 一 问题背景 二 启用SPI的DMA传输 2 1 修改cfg main h 文件 2 2 make menuconfig 配置SPI 2 3 修改SPI主机驱动代码 2 4 增加设备
  • vue cmd 创建新项目在指定文件夹

    1 cmd 进入 后 转到指定目录 cd D 2 创建vue新项目 vue create test
  • 基于minikube搭建的SpringBoot实战

    现在比较多的互联网公司都在尝试将微服务迁到云上 这样的能够通过一些成熟的云容器管理平台更为方便地管理微服务集群 从而提高微服务的稳定性 同时也能较好地提升团队开发效率 但是迁云存在一定的技术难点 今天这篇文章主要介绍如何从0开始搭建一套基于
  • 我的世界服务器修改空岛范围,我的世界空岛指令权限大全

    发布时间 2016 08 07 我的世界ess指令是什么 我的世界ess指令在ess插件运行中十分重要的一部分 那么今天小编就为大家带来了我的世界ess指令用法大全 一起看看吧 我的世界ess指令 Essentials插件 用户组权限管理插
  • OTA:目标检测的最优运输分配

    引言 该论文主要是关于目标检测中的标签分配问题 作者创新性地从全局的角度重新审视了该问题 并提出将标签分配问题看成是一个最优运输问题 要知道最优传输问题是当前最优化理论和GAN理论研究领域中的一个很火的研究课题 论文的实验效果俱佳 而且作者
  • redis系列,redis是如何执行命令(一)

    文章目录 前言 一 从io读取数据 二 解析buf数据 三 解析命令流程 总结 前言 上篇文章介绍了sds的结构 和sds的使用方法 这章我们在回到读取io数据的地方来看 redis是如何从io 读取数据最后转化成执行命令的过程 本篇文章需
  • 计量经济学及Stata应用 第三章习题

    3 1 对于随机变量X 证明Var X E x2 E X 2 3 2对于随机变量X与Y 证明Cov X Y E XY E X E Y 3 3对于随机变量X Y Z 证明Cov X Y Z Cov X Y Cov X Z 3 4 二维随机向量
  • MySQL----MySQL数据库出现Lost connection to MySQL server during query错误的解决办法

    原文链接 MySQL MySQL数据库出现Lost connection to MySQL server during query错误的解决办法 问题描述 Mysql数据库在查询数据库的时候回报出了如下异常 Lost connection
  • Winsock 2 I/O Methods 5 Part 11

    Winsock 2 I O Methods 5 Part 11 What do we have in this chapter 5 part 11 Testing the Client server Program Completion P