一个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
文章中相关的完整源码下载地址:
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.
相关推荐
此代码http://download.csdn.net/source/1101107 的新版本,修改了一些不过,但udp server还存在问题,发布此代码的目的就是做技术交流,还希望大虾能知道一下小弟。
多线程IOCP服务器
高效率IOCP的UDP通信服务端,基于IOCP的为管理容器的线程池,提供取出与加入以及线程池大小的操作
用VC++编写的稳定高效tcp/udp iocp服务器及客户端。用VC++编写的稳定高效tcp/udp iocp服务器及客户端。
IOCP作为服务器实现P2P_UDP通信工具
UDP+IOCP完成端口实现多播.zip
iocp_tcp服务端.rar
封装类源代码,其中TCP服务器多线程监听功能、客户端支持断线重连、多线程串口读写、命名管道监听已经实现。UDP、并口等参考后也较容易实现。特别数据包头解析部分,已经支持多种类型:包头(含数据长度)、特殊类型...
iocp服务器代码,一个是只有接收的,还有一个是接受后会发回 tcp&udp;并行压力测试工具 质量杠杠的
IOCP 接收线程和工作线程 IOCP 接收线程和工作线程 IOCP 接收线程和工作线程
易语言IOCP与TCP套接字源码,IOCP与TCP套接字,创建,销毁,投递任务,子程序_服务端_处理上线信息,子程序_服务端_创建服务端套接字,子程序_服务器_投递接收客户事件,子程序_指针正确否,子程序_设置套接字,取核心数,Call_...
易语言源码易语言IOCP与TCP套接字源码.rar
封装类源代码,其中TCP服务器多线程监听功能、客户端支持断线重连、多线程串口读写、命名管道监听已经实现。UDP、并口等参考后也较容易实现。特别数据包头解析部分,已经支持多种类型:包头(含数据长度)、特殊类型...
UDP多播IOCP的客户设计经典代码IOCP client UDP multicast design classic code
IOCP多线程socket模型,包括server和client的demo,收藏一下。
应用程序向导已为您创建了此 IOCPServer 应用程序。此应用程序不仅演示 Microsoft 基础类的基本使用方法,还可作为您编写应用程序的起点。
易语言iocp_tcp服务端源码,iocp_tcp服务端,call,内存_读整数,内存_写整数,取CPU核心数量,创建堆,销毁堆,取内存,还内存,IOCP_启动,IOCP_销毁,IOCP_处理线程,IOCP_取回用户,IOCP_发送数据,IOCP_断开连接,PostAcceptEx,...
用完成端口IOCP实现的socket服务端引擎和多线程客户端引擎.zip
tcp与udp的整合实现,只是为了自己项目的方便而做,完全可以分开实现。在此基础上将在后期开发p2p视频聊天,文件传输(RUDP)等软件。大虾见笑了,希望对初学者有所帮助。
基于IOCP模型的无锁0内核态TCP通讯服务器引擎(IOCPTCP Server)