`
aigo
  • 浏览: 2678540 次
  • 性别: Icon_minigender_1
  • 来自: 宜昌
社区版块
存档分类
最新评论

多线程IOCP实现的TCP和UDP server示例

阅读更多

一个IOCP TCP server的例子:

http://www.codeproject.com/Articles/10330/A-simple-IOCP-Server-Client-Class

 

 

一个IOCP UDP server的例子

Winsock Registered I/O - Traditional Multi threaded IOCP UDP Example Server

http://www.serverframework.com/asynchronousevents/2012/08/winsock-registered-io---traditional-multi-threaded-iocp-udp-example-server.html

 

文章中相关的完整源码下载地址:

https://yunpan.cn/cqh6SML8zSrtt  访问密码 d0df

 

This article presents the sixth in my series of example servers for comparing the performance of the Winsock Registered I/O Networking extensions, RIO, and traditional Windows networking APIs. This example server is a traditional multi-threaded, IOCP based, UDP design that we can use to compare to the multi-threaded RIO IOCP UDP example server. I've been looking at the Winsock Registered I/O Networking Extensions since October when they first made an appearance as part of the Windows 8 Developer Preview, though lately most of my testing has been using Windows Server 2012 RC. Whilst exploring and understanding the new API I spent some time putting together some simple UDP servers using the various notification styles that RIO provides. I then put together some equally simple UDP servers using the "traditional" APIs so that I could compare performance. This series of blog posts describes each of the example servers in turn. You can find an index to all of the articles about the Winsock Registered I/O example servers here.
 
A traditional multi-threaded IOCP UDP server
This server is structured in a similar way to the other example servers and uses the same shared helper code and limited error handling (see here for more details). We start by initialising things in a similar way to the other servers.
 
int _tmain(int argc, _TCHAR* argv[])
{
   if (argc > 2)
   {
      cout << "Usage: IOCPUDPMT [workLoad]" << endl;
   }
 
   if (argc > 1)
   {
      g_workIterations = _ttol(argv[1]);
   }
 
   SetupTiming("IOCP UDP MT");
 
   InitialiseWinsock();
 
   SOCKET s = CreateSocket(WSA_FLAG_OVERLAPPED);
 
   HANDLE hIOCP = CreateIOCP();
 
   if (0 == ::CreateIoCompletionPort(
      reinterpret_cast<HANDLE>(s),
      hIOCP,
      1,
      0))
   {
      ErrorExit("CreateIoCompletionPort");
   }
 
   Bind(s, PORT);
 
   PostIOCPRecvs(RECV_BUFFER_SIZE, IOCP_PENDING_RECVS);
 
   CreateIOCPThreads(NUM_IOCP_THREADS);
 
   WaitForProcessingStarted();
 
   WaitForProcessingStopped();
 
   StopIOCPThreads();
 
   PrintTimings();
}
 
To help simulate servers that actually do some work with each datagram we can pass a command line argument to control how much 'busy work' we do for each datagram.
 
Once we have the socket created and bound we need to post some read requests. This involves creating and managing a set of buffers in a similar way to what we do for the RIO server; though we don't need to register these buffers before performing I/O with them.
 
inline void PostIOCPRecvs(
   const DWORD recvBufferSize,
   const DWORD pendingRecvs)
{
   DWORD totalBuffersAllocated = 0;
 
   while (totalBuffersAllocated < pendingRecvs)
   {
      DWORD receiveBuffersAllocated = 0;
 
      char *pBuffer = AllocateBufferSpace(
         recvBufferSize,
         pendingRecvs,
         receiveBuffersAllocated);
 
      totalBuffersAllocated += receiveBuffersAllocated;
 
      DWORD offset = 0;
 
      const DWORD recvFlags = 0;
 
      EXTENDED_OVERLAPPED *pBufs = new EXTENDED_OVERLAPPED[receiveBuffersAllocated];
 
      DWORD bytesRecvd = 0;
      DWORD flags = 0;
 
      for (DWORD i = 0; i < receiveBuffersAllocated; ++i)
      {
         EXTENDED_OVERLAPPED *pOverlapped = pBufs + i;
 
         ZeroMemory(pOverlapped, sizeof(EXTENDED_OVERLAPPED));
 
         pOverlapped->buf.buf = pBuffer + offset;
         pOverlapped->buf.len = recvBufferSize;
 
         offset += recvBufferSize;
 
         if (SOCKET_ERROR == ::WSARecv(
            g_s,
            &(pOverlapped->buf),
            1,
            &bytesRecvd,
            &flags,
            static_cast<OVERLAPPED *>(pOverlapped), 0))
         {
            const DWORD lastError = ::GetLastError();
 
            if (lastError != ERROR_IO_PENDING)
            {
               ErrorExit("WSARecv", lastError);
            }
         }
      }
 
      if (totalBuffersAllocated != pendingRecvs)
      {
         cout << pendingRecvs << " receives pending" << endl;
      }
   }
 
   cout << totalBuffersAllocated << " total receives pending" << endl;
}
 
 
We're using the same buffer allocation code as the earlier RIO servers, so see here for more details or download the code at the end of this article.
 
We then create our worker threads and start everything up. The main work is done in the worker thread function shown below.
unsigned int __stdcall ThreadFunction(
   void *pV)
{
#ifdef TRACK_THREAD_STATS
   const DWORD index = (DWORD)(ULONG_PTR)pV;
 
   ThreadData &threadData = g_threadData[index];
 
   threadData.threadId = ::GetCurrentThreadId();
 
   threadData.maxPacketsProcessed = 1;
   threadData.minPacketsProcessed = 1;
#endif
 
   DWORD numberOfBytes = 0;
 
   ULONG_PTR completionKey = 0;
 
   OVERLAPPED *pOverlapped = 0;
 
   if (!::GetQueuedCompletionStatus(
      g_hIOCP,
      &numberOfBytes,
      &completionKey,
      &pOverlapped,
      INFINITE))
   {
      ErrorExit("GetQueuedCompletionStatus");
   }
 
   int workValue = 0;
 
   if (completionKey == 1)
   {
      bool done = false;
 
      ::SetEvent(g_hStartedEvent);
 
      DWORD bytesRecvd = 0;
      DWORD flags = 0;
 
      do
      {
#ifdef TRACK_THREAD_STATS
         threadData.dequeueCalled++;
 
         threadData.packetsProcessed++;
#endif
 
         if (numberOfBytes == EXPECTED_DATA_SIZE)
         {
            ::InterlockedIncrement(&g_packets);
 
            workValue += DoWork(g_workIterations);
 
            EXTENDED_OVERLAPPED *pExtOverlapped = static_cast<EXTENDED_OVERLAPPED *>(pOverlapped);
 
            if (SOCKET_ERROR == ::WSARecv(
               g_s,
               &(pExtOverlapped->buf),
               1,
               &bytesRecvd,
               &flags,
               pExtOverlapped,
               0))
            {
               const DWORD lastError = ::GetLastError();
 
               if (lastError != ERROR_IO_PENDING)
               {
                  ErrorExit("WSARecv", lastError);
               }
            }
 
            done = false;
 
         }
         else
         {
            done = true;
         }
 
         if (!done)
         {
            if (!::GetQueuedCompletionStatus(
               g_hIOCP,
               &numberOfBytes,
               &completionKey,
               &pOverlapped,
               INFINITE))
            {
               const DWORD lastError = ::GetLastError();
 
               if (lastError != ERROR_OPERATION_ABORTED)
               {
                  ErrorExit("GetQueuedCompletionStatus", lastError);
               }
            }
 
            if (completionKey == 0)
            {
               done = true;
            }
         }
      }
      while (!done);
   }
 
   ::SetEvent(g_hStoppedEvent);
 
   return workValue;
}
 
We've added some optional stats collection as this has proved useful in reasoning about the relative performance of the IOCP servers. These stats are now displayed along with the timings at the end of the test.
 
The code for this example can be downloaded from here. This code requires Visual Studio 2012, but would work with earlier compilers if you have a Windows SDK that supports RIO. Note that Shared.h and Constants.h contain helper functions and tuning constants for ALL of the examples and so there will be code in there that is not used by this example. You should be able to unzip each example into the same directory structure so that they all share the same shared headers. This allows you to tune all of the examples the same so that any performance comparisons make sense.
 

Join in

Comments and suggestions are more than welcome. I'm learning as I go here and I'm quite likely to have made some mistakes or come up with some erroneous conclusions, feel free to put me straight and help make these examples better.

 

分享到:
评论

相关推荐

    基于IOCP模型实现TCP服务器、客户端,串口、命名管道等类库(例子)

    封装类源代码,其中TCP服务器多线程监听功能、客户端支持断线重连、多线程串口读写、命名管道监听已经实现。UDP、并口等参考后也较容易实现。特别数据包头解析部分,已经支持多种类型:包头(含数据长度)、特殊类型...

    iocp服务器代码_tct&udp;测试工具

    本资源包含了一个基于IOCP的服务器代码示例,以及一个用于TCP和UDP并行压力测试的工具。 首先,让我们详细了解一下IOCP(I/O完成端口)。IOCP是一种高级的I/O模型,它允许多个线程并发处理I/O操作的完成。在传统的I...

    网络lib与实例,使用IOCP

    在提供的“web应用实例与lib”中,我们可以看到实际的代码实现,这些示例可能包含了如何创建和管理IOCP,如何处理TCP和UDP的连接,以及如何进行数据的加密和解密,以及封包和解包的逻辑。通过对这些代码的学习和理解...

    IOCP的Socket 服务器端源码

    在本示例中,"IOCP的Socket服务器端源码"是基于IOCP实现的一个游戏服务器端程序,能够支持TCP/IP和UDP两种网络协议,并且在VC++环境中进行开发。** **TCP/IP是一种广泛使用的网络通信协议栈,由传输层的TCP...

    C# IOCP完成端口模型(简单实用高效)

    `5692829_IocpServer.zip`这个文件可能包含了示例代码,演示如何在C#中实现一个基于IOCP的TCP服务器。解压并研究这个文件,你可以看到如何将上述理论应用于实际项目,例如如何创建和管理完成端口,如何设置I/O回调,...

    async-sockets-cpp:C ++中基于简单线程的异步TCP和UDP套接字类

    `async-sockets-cpp`库提供了一个简洁的API,使得开发者能够轻松地利用多线程实现异步TCP和UDP套接字操作。这个库的核心目标是简化网络编程的复杂性,同时保持性能和可扩展性。 首先,让我们了解一下异步套接字的...

    ipv6_ipv4_IOCP.zip

    "IPV6TCPSOCKET"和"IPv6_UDP"可能包含了使用IOCP实现的IPv6 TCP和UDP客户端示例代码。在TCP编程中,IOCP结合`WSAEventSelect`或`WSAAsyncSelect`可以创建异步的套接字事件处理机制,允许程序在一个套接字上监听多个...

    基于UDP协议的简单服务端和客户端示例

    5. **多线程/异步处理**:为了处理多个并发的客户端请求,服务器端可能需要使用多线程或异步IO模型,例如使用Linux的epoll或Windows的IOCP。 6. **数据报的不可靠性**:由于UDP不保证数据的顺序或完整性,所以在...

    UDP完成端口 Demo (改)

    IOCP是Windows系统中用于提高多线程环境下的I/O操作性能的一种机制,尤其适合于高并发的网络服务器应用,如UDP服务。在这个Demo中,开发者可能已经解决了原版代码中无法真正实现并发的问题,使其能够充分利用多核...

    HP-Socket TCP & UDP 通信框架开发指南 5.0

    HP-Socket是一套通用的高性能TCP/UDP/HTTP通信框架,专为解决网络通信中的各种需求而设计,支持多种编程语言接口,如C/C++、C#、Delphi、易语言、Java和Python。该框架的主要特色在于其封装了底层网络通信细节,提供...

    集成windows iocp到libevent

    IOCP是Windows操作系统提供的一种多线程异步I/O机制。它允许应用程序在一个或多个线程上处理大量的I/O操作,而无需阻塞主线程。当一个I/O操作完成时,系统会将结果放入一个队列,然后唤醒等待的线程来处理结果。这种...

    IOCP.rar_IOCP_easy

    9. **多线程编程**:理解线程间的协作和同步机制,如事件、互斥量等,是使用IOCP的关键。 10. **实际应用**:了解如何在实际项目中集成IOCP,如网络编程中的TCP/UDP服务器,以及磁盘I/O优化等。 由于没有具体的...

    iocp.rar_IOCP_IOCP windows

    在网络编程中,IOCP常用于TCP和UDP服务端。通过使用IOCP,服务器可以处理大量并发连接,实现高吞吐量和低延迟的通信。在`network.sln`这个项目中,可能包含了实现IOCP模型的网络服务代码,如服务器的启动、客户端...

    C# IOCP通讯封装透传的,需要自己做分包处理

    IOCP(I/O完成端口)通过将I/O操作提交到一个共享的I/O端口,允许多个线程等待同一事件,从而提高系统性能。在TCP/IP通信中,IOCP可以显著提升服务器处理大量并发连接的能力,避免阻塞问题,提高系统的响应速度。 ...

    蓝色枫叶IOCP网络支持库

    IOCP(Input/Output Completion Port)的核心概念在于将I/O操作与线程解耦,使得一个线程可以处理多个I/O完成事件,而无需为每个I/O请求分配单独的线程。这样极大地减少了线程创建和销毁的开销,同时也避免了线程上...

    多线程端口扫描器(含源代码)

    综上所述,多线程端口扫描器是一个结合了多线程技术、网络编程、并发控制和错误处理等多个领域的项目,对于学习和提升这些技能具有很高的价值。通过深入研究和改进这个草稿文件,开发者可以更好地理解并掌握这些核心...

    IOCP_API(1.2.1.3)

    总结起来,IOCP_API 1.2.1.3版本在内存管理、接口设计、面向对象封装以及示例项目方面都进行了优化,旨在提供一个高效、易用且强大的网络编程框架,特别适合开发需要处理高并发连接的TCP/UDP服务器应用。结合MFC...

    易语言学习-IOCP服务器模型支持库1.6稳定版.zip

    2. **网络通信模块**:实现TCP或UDP协议栈,便于用户处理网络连接和数据传输。可能包括连接管理、数据包封装和解封装、错误处理等功能。 3. **线程池**:为了有效地调度I/O操作,支持库可能会包含一个线程池,用于...

    Windows高性能大并发IOCP

    通讯协议部分是网络通信的基础,本示例可能包含了自定义的TCP或UDP协议实现。这些协议通常包括数据的编码和解码、错误检测和纠正、流量控制等机制,以确保数据的正确传输。可能还涉及到心跳机制,用于检查网络连接...

    windows网络编程示例代码

    Windows网络编程第二版的示例代码提供了丰富的实践案例,帮助开发者深入理解网络通信的基本原理和实现方法。下面我们将详细探讨其中的关键知识点。 一、Windows Socket API Windows Socket,简称Winsock,是Windows...

Global site tag (gtag.js) - Google Analytics