完成端口的一个例子

《完成端口(CompletionPort)详解》源码 文章在此:https://blog.youkuaiyun.com/piggyxp/article/details/6922277 原文的源码缺失,在此补上。 立即下载
 

来自微软的完成端口例子,就讲解一下它的使用套路吧
反正编程这个玩意,只要用过,自然就知道什么回事,一次不会再看一次,学习这个玩意,无他,勤奋而已。
奢谈效率等等,那只是孰能生巧上的功夫。
 

  这个例子是在console下的例子,算是一个echo服务器吧,
  跑起来后将在5150端口监听,一旦有个端口连接上来,发个数据给服务端口,它就echo回数据给那个端口. 直到那个连接中断.
 
 完成端口,其实理解成一个通道或管子就可以了,和管道也差不了多少,不过可以实现异步处理罢了,
 你这边往管子里丢数据,通过GetQueuedCompletionStatus来查管子那头出数据没,出了就处理,这个管子就是通过一个自定义有点特殊的结构来写入或读出数据而已.
 那个完成端口,其实就相当是标识那个数据块的句柄,

//下面请看例子
#i nclude <winsock2.h>
#i nclude <windows.h>
#i nclude <stdio.h>

#define PORT 5150
#define DATA_BUFSIZE 8192

#pragma comment(lib, "Ws2_32")

typedef struct                        //这个玩意就是灌数据,取数据的一个自定义数据结构

                                              //和那个wm_data差不了多少,不过就是老要塞一个OverLapped结构,
{
   OVERLAPPED Overlapped;
   WSABUF DataBuf;
   CHAR Buffer[DATA_BUFSIZE];                    
   DWORD BytesSEND;                                 //发送字节数
   DWORD BytesRECV;                                
} PER_IO_OPERATION_DATA, * LPPER_IO_OPERATION_DATA;


typedef struct
{
   SOCKET Socket;
} PER_HANDLE_DATA, * LPPER_HANDLE_DATA;


DWORD WINAPI ServerWorkerThread(LPVOID CompletionPortID);


void main(void)
{
   SOCKADDR_IN InternetAddr;
   SOCKET Listen;
   SOCKET Accept;
   HANDLE CompletionPort;
   SYSTEM_INFO SystemInfo;
   LPPER_HANDLE_DATA PerHandleData;
   LPPER_IO_OPERATION_DATA PerIoData;
   int i;
   DWORD RecvBytes;
   DWORD Flags;
   DWORD ThreadID;
   WSADATA wsaData;
   DWORD Ret;

   if ((Ret = WSAStartup(0x0202, &wsaData)) != 0)
   {
      printf("WSAStartup failed with error %d/n", Ret);
      return;
   }

   //
   //完成端口的建立得搞2次,这是第一次调用,至于为什么?我问问你
   //
   if ((CompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0)) == NULL)
   {
      printf( "CreateIoCompletionPort failed with error: %d/n", GetLastError());
      return;
   }
   //老套子api,不谈也罢
   GetSystemInfo(&SystemInfo);
  
   //发现2个CPU,那就开个双倍的线程跑吧
   for(i = 0; i < SystemInfo.dwNumberOfProcessors * 2; i++)
   {
      HANDLE ThreadHandle;
     
      //
      //完成端口挂到线程上面来了,就像管子把灌数据的和读数据的两头都连上了,           
     //
      if ((ThreadHandle = CreateThread(NULL, 0, ServerWorkerThread, CompletionPort,
         0, &ThreadID)) == NULL)
      {
         printf("CreateThread() failed with error %d/n", GetLastError());
         return;
      }     
      CloseHandle(ThreadHandle);
   }

   //
   //启动一个监听socket ,以下都是长长的交代
   //
   if ((Listen = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0,
      WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)
   {
      printf("WSASocket() failed with error %d/n", WSAGetLastError());
      return;
   }

   InternetAddr.sin_family = AF_INET;
   InternetAddr.sin_addr.s_addr = htonl(INADDR_ANY);
   InternetAddr.sin_port = htons(PORT);

   if (bind(Listen, (PSOCKADDR) &InternetAddr, sizeof(InternetAddr)) == SOCKET_ERROR)
   {
      printf("bind() failed with error %d/n", WSAGetLastError());
      return;
   }  

   if (listen(Listen, 5) == SOCKET_ERROR)
   {
      printf("listen() failed with error %d/n", WSAGetLastError());
      return;
   }

   //
   // 监听端口打开,就开始在这里循环,一有socket连上,WSAAccept就创建一个socket,
   // 这个socket 又和完成端口联上,
   //
   // 嘿嘿,完成端口第二次调用那个createxxx函数,为什么,留给人思考思考可能更深刻,
   // 反正这套路得来2次,
   // 完成端口completionport和accept socket挂起来了,
   //
   while(TRUE)
   {

    //主线程跑到这里就等啊等啊,但是线程却开工了,
      if ((Accept = WSAAccept(Listen, NULL, NULL, NULL, 0)) == SOCKET_ERROR)
      {
         printf("WSAAccept() failed with error %d/n", WSAGetLastError());
         return;
      }
     
      if ((PerHandleData = (LPPER_HANDLE_DATA) GlobalAlloc(GPTR, sizeof(PER_HANDLE_DATA))) == NULL)
      {
         printf("GlobalAlloc() failed with error %d/n", GetLastError());
         return;
      }     
     
      PerHandleData->Socket = Accept;
     
      //
     //把这头和完成端口completionPort连起来
     //就像你把漏斗接到管子口上,开始要灌数据了
     //
      if (CreateIoCompletionPort((HANDLE) Accept, CompletionPort, (DWORD) PerHandleData,
         0) == NULL)
      {
         printf("CreateIoCompletionPort failed with error %d/n", GetLastError());
         return;
      }
     
      //
      //清管子的数据结构,准备往里面灌数据
      //
      if ((PerIoData = (LPPER_IO_OPERATION_DATA) GlobalAlloc(GPTR,sizeof(PER_IO_OPERATION_DATA))) == NULL)
      {
         printf("GlobalAlloc() failed with error %d/n", GetLastError());
         return;
      }

      ZeroMemory(&(PerIoData->Overlapped), sizeof(OVERLAPPED));
      PerIoData->BytesSEND = 0;
      PerIoData->BytesRECV = 0;
      PerIoData->DataBuf.len = DATA_BUFSIZE;
      PerIoData->DataBuf.buf = PerIoData->Buffer;

      Flags = 0;
     
      //
      //  accept接到了数据,就放到PerIoData中,而perIoData又通过线程中的函数取出,
     //
      if (WSARecv(Accept, &(PerIoData->DataBuf), 1, &RecvBytes, &Flags,
         &(PerIoData->Overlapped), NULL) == SOCKET_ERROR)
      {
         if (WSAGetLastError() != ERROR_IO_PENDING)
         {
            printf("WSARecv() failed with error %d/n", WSAGetLastError());
            return;
         }
      }
   }
}

//
//线程一但调用,就老在里面循环,
// 注意,传入的可是完成端口啊,就是靠它去取出管子中的数据
//
DWORD WINAPI ServerWorkerThread(LPVOID CompletionPortID)
{
   HANDLE CompletionPort = (HANDLE) CompletionPortID;
  
   DWORD BytesTransferred;
   LPOVERLAPPED Overlapped;
   LPPER_HANDLE_DATA PerHandleData;
   LPPER_IO_OPERATION_DATA PerIoData;        
   DWORD SendBytes, RecvBytes;
   DWORD Flags;
 
   while(TRUE)
   {
      //
      //在这里检查完成端口部分的数据buf区,数据来了吗?
      // 这个函数参数要看说明,
      // PerIoData 就是从管子流出来的数据,
      //PerHandleData 也是从管子里取出的,是何时塞进来的,
     //就是在建立第2次createIocompletionPort时
    // 

      if (GetQueuedCompletionStatus(CompletionPort, &BytesTransferred,
         (LPDWORD)&PerHandleData, (LPOVERLAPPED *) &PerIoData, INFINITE) == 0)
      {
         printf("GetQueuedCompletionStatus failed with error %d/n", GetLastError());
         return 0;
      }

      // 检查数据传送完了吗
      if (BytesTransferred == 0)
      {
         printf("Closing socket %d/n", PerHandleData->Socket);

         if (closesocket(PerHandleData->Socket) == SOCKET_ERROR)
         {
            printf("closesocket() failed with error %d/n", WSAGetLastError());
            return 0;
         }

         GlobalFree(PerHandleData);
         GlobalFree(PerIoData);
         continue;
      }    
     //
    //看看管子里面有数据来了吗?=0,那是刚收到数据
    //
      if (PerIoData->BytesRECV == 0)
      {
         PerIoData->BytesRECV = BytesTransferred;
         PerIoData->BytesSEND = 0;
      }
      else   //来了,
      {
         PerIoData->BytesSEND += BytesTransferred;
      }
  
      //
      // 数据没发完?继续send出去
     //
     if (PerIoData->BytesRECV > PerIoData->BytesSEND)
      {

         ZeroMemory(&(PerIoData->Overlapped), sizeof(OVERLAPPED)); //清0为发送准备
         PerIoData->DataBuf.buf = PerIoData->Buffer + PerIoData->BytesSEND;
         PerIoData->DataBuf.len = PerIoData->BytesRECV - PerIoData->BytesSEND;

       //1个字节一个字节发送发送数据出去
         if (WSASend(PerHandleData->Socket, &(PerIoData->DataBuf), 1, &SendBytes, 0,
            &(PerIoData->Overlapped), NULL) == SOCKET_ERROR)
         {
            if (WSAGetLastError() != ERROR_IO_PENDING)
            {
               printf("WSASend() failed with error %d/n", WSAGetLastError());
               return 0;
            }
         }
      }
      else
      {
         PerIoData->BytesRECV = 0;

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

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

         if (WSARecv(PerHandleData->Socket, &(PerIoData->DataBuf), 1, &RecvBytes, &Flags,
            &(PerIoData->Overlapped), NULL) == SOCKET_ERROR)
         {
            if (WSAGetLastError() != ERROR_IO_PENDING)
            {
               printf("WSARecv() failed with error %d/n", WSAGetLastError());
               return 0;
            }
         }
      }
   }
}

完成端口(IOCP)精简实例 精简的C++完成端口小例子 包括客户端和服务器端 适合初学者 立即下载

相关推荐

完成端口实例

将Socket和完成端口操作集成于一个类CComplatePortSocket中。提供服务端和客户端测试代码。

完成端口(一个小例子,供学习用!)

完成端口一、什么是完成端口从本质上讲,完成端口是一种异步I/O技术,它提供一个内核对象,可以关联多个I/O设备,同时关联一个线程池,线程池中的线程通常处于睡眠状态,当有I/O出现时,完成端口唤醒等待线程队列中的线程进行处理。完成端口有着良好的伸缩性灵活性以及较高的效率,一般用来创建大型的服务器。我们知道,一个服务器应用程序结构可以分为串行模式和并发模式。在串行模式中,一次只能处理一个请

1764

一个很好的完成端口(IOCP)例子

面的代码包括编写的完成端口服务器端的代码,还包括一个对服务器端进行压力测试的客户端,以及一个普通的客户端。并且带有非常详尽的代码注释的。

完成端口(CompletionPort)详解 - 手把手教你玩转网络编程系列之三

手把手叫你玩转网络编程系列之三    完成端口(Completion Port)详解                                                              ----- By PiggyXP(小猪) 前 言         本系列里完成端口的代码在两年前就已经写好了,但是由于许久没有写东西了,不知该如何提笔,所以这篇文档总是在酝酿

小猪的网络编程 22万+

完成端口服务器的一个例子

TCPIP 服务器五种I/O操作的完成端口的例子

IOCPExample_By_PiggyXP 完成端口示例代码

完成端口示例代码:IOCPExample_By_PiggyXP.rar

初学完成端口的实例代码

////////////////////////////////////////////////////////////////////////////  完成端口//////////////////////////////////////////////////////////////////////////////#include "stdafx.h"#include #include #

程序的江湖?! 勿在浮砂筑高台! 1864

一个简单的完成端口例子(IOCPDemo)适合初学者参考

一个简单的完成端口例子(IOCPDemo)适合初学者参考

完成端口(iocp)的一个例子

<br /> <br />来自微软的完成端口例子,就讲解一下它的使用套路吧<br />反正编程这个玩意,只要用过,自然就知道什么回事,一次不会再看一次,学习这个玩意,无他,勤奋而已。<br />奢谈效率等等,那只是孰能生巧上的功夫。<br />  这个例子是在console下的例子,算是一个echo服务器吧,<br />  跑起来后将在5150端口监听,一旦有个端口连接上来,发个数据给服务端口,它就echo回数据给那个端口. 直到那个连接中断.<br />  <br /> 完成端口,其实理解成一个通道或管子

懒人的技术笔记 2789

手把手教你用Arduino搭建惠斯通电桥:从原理到代码实现(附完整电路图)

本文详细介绍了如何利用Arduino搭建惠斯通电桥,从硬件选型、电路设计到代码实现和校准技巧,提供完整的电路图和实用代码示例。特别适合电子爱好者和创客学习高精度电阻测量技术,并扩展应用于应变片测量和温度监测等实际项目。

o4p5q6r7s的博客 402

单细胞转录组聚类分析R包——SC3的应用

前言 在做单细胞相关聚类分析的过程中,为了研究异质性,发现了一种专门用于单细胞转录组的聚类分析R包——SC3(single cell consensus clustering,单细胞一致性聚类)。该聚类算法发表于Nature Methods(2017),能够让单细胞RNA-seq基于转录组特征对细胞类型进行定量表征。这是一种用户友好的无监督聚类工具,它通过一致方法将多个聚类解决方案组合在一起,从而得到高精度和鲁棒性的分群结果。SC3包的官方具体使用教程见:http://www.bioconductor.or

m0_51042606的博客 5005

用完成端口(iocp) 写的一个简单的服务端例子

下面是用完成端口写的一个简单的 例子, 完成端口和重叠io 一样都是异步io。 代码如下。欢迎大家建议 改进、

C++编程的专栏 2662

prometheus 从入门到精通(史上最全)

Prometheus(由go语言开发)是一套开源的监控&报警&时间序列(按照时间排序)数据库的组合。因为kubernetes(俗称k8s)的流行带动了prometheus的发展。它可以监控主机,服务,容器,支持多种exporter采集数据,还支持pushgateway进行数据上报,Prometheus性能足够支撑上万台规模的集群。原文链接:https://blog.youkuaiyun.com/qq_45277554/article/details/130917620时间序列数据。

流水_鱼鱼的博客 1万+

socket编程之完成端口(附一个简单的IOCP例子)

“完成端口”模型是迄今为止最为复杂的—种I/O模型。然而。假若—个应用程序同时需要管理为数众多的套接字,那么采用这种模型。往往可以达到最佳的系统性能,然而不幸的是,该模型只适用于以下操作系统(微软的):Windows NT和Windows 2000操作系统。因其设计的复杂性,只有在你的应用程序需要同时管理数百乃至上千个套接字的时候、而且希望随着系统内安装的CPU数量的增多、应用程序的性能也可以线性

AyLe0n的专栏 1321

SAP PCC成本收集器实战:从配置到结算的完整流程解析

本文详细解析了SAP PCC成本收集器从配置到结算的完整流程,特别适用于重复制造行业。通过实战案例和配置要点,帮助用户掌握物料分类账管理、成本中心费用归集及差异分析等核心功能,提升企业生产成本控制效率。

weixin_29251567的博客 896

计算机组成原理实验:手把手教你用模拟程序实现中断机制(附完整代码)

本文通过一个计算机组成原理模拟实验,手把手教你从零实现一个可工作的中断系统。实验详细演示了如何配置中断控制器、编写主程序与中断服务程序,并观察中断响应、现场保护和恢复的全过程,深入解析了中断原理的核心机制。

471
上一篇: 完成端口(I/O completion):
下一篇: Visual Studio 2005创建VC++智能设备项目失败的解决方法
ventry
博客等级 码龄21年 15粉丝 30原创
评论 5
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值