详解IOCPServer源码实现原理 (iocp服务器源码)

IOCPServer源码实现原理详解

IOCP,即Input/Output Completion Port,是微软在Windows平台上实现异步IO模型的一种技术。IOCPServer是基于IOCP技术实现的服务器框架,它通过使用IOCP技术实现高性能的异步网络通信,支持并发处理大量客户端请求。本文将从源码分析的角度详细解读IOCPServer的实现原理。

一、IOCP技术介绍

IOCP技术是微软在Windows平台上解决高并发网络通信问题的一种有效手段。传统的网络通信都采用同步阻塞方式,即一个客户端连接上来后,需要等待服务器处理完后才能与下一个客户端建立连接。针对这种问题,IOCP技术引入了异步IO模型。

使用IOCP技术的异步IO模型是由操作系统来完成真正的IO操作,应用程序只需在IOCP对象上投递IO请求,待操作系统完成IO请求后,应用程序的工作线程才会被唤醒,即回调函数才会被调用,从而返回IO处理结果。因此,IOCP技术的异步IO模型能够达到高并发,处理的连接数可以远远超过传统的同步阻塞模式。

二、IOCPServer框架介绍

IOCPServer框架是基于IOCP技术实现的服务器框架,它支持并发处理大量客户端请求。它的实现原理是和传统的网络服务端实现有所不同的。在传统的实现方式下,网络服务端需要为每一个客户端创建一个线程或者进程进行处理。

而IOCPServer基于IOCP技术实现了异步IO操作,使用了新的线程池机制,将真正的IO操作交给系统内核来完成,避免了频繁的线程或进程的创建与销毁,从而大大提高了服务端的并发处理能力。下面我们将详细介绍IOCPServer的实现原理。

三、IOCPServer的IOCP对象

在IOCPServer的实现中,IOCP对象充当着非常重要的角色,它是实现异步IO通信的基础。IOCP对象本身是一个操作系统内核对象,任何在网络通信中需要异步IO的操作,都需要通过IOCP对象来完成。

在IOCPServer的实现中,使用CreateIoCompletionPort函数来创建IOCP对象,并将需要进行异步IO操作的套接字(Socket)与IOCP对象关联起来。这样,当某个套接字发生异步IO事件时,系统内核就会往该IOCP对象上投递IO完成事件,应用程序可以通过GetQueuedCompletionStatus函数来获取IO完成的结果。

下面是一个简单的创建IOCP对象的示例代码:

HANDLE hIOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);

四、IOCPServer的线程池

由于IOCP对象投递的IO事件是异步的,因此,当IO事件发生后,应用程序的工作线程并不能立即获得IO的结果。在IOCPServer的实现中,需要使用线程池机制来管理工作线程,从而实现真正的异步IO操作。

当客户端连接上来后,服务端会开始投递IO请求,而这些IO请求都需要在线程池中的工作线程中来完成。在线程池中的每一个工作线程都会不断的从IOCP对象中获取IO请求的结果,并通过回调函数来处理这些请求。

在IOCPServer的实现中,线程池的大小是通过配置文件来进行设置的。该设置指定了线程池最少的线程数量,更大的线程数量和空闲时间。如果IO请求量较小,线程池会自动销毁多余的线程,以节约系统资源。如果IO请求量增加,线程池则会自动创建新的线程。

下面是一个简单的创建线程池的示例代码:

ThreadPool::GetInstance().Create(10, 50, 30);

五、IOCPServer的业务逻辑处理

在IOCPServer的实现中,真正的业务逻辑处理是在工作线程池中完成的。当客户端请求到来后,服务端会首先将IO请求投递到IOCP对象中,并由工作线程池中的工作线程来执行相应的业务逻辑处理。

工作线程在执行业务逻辑时,需要处理不同的请求类型。在IOCPServer中,支持TCP和UDP两种协议。对于TCP协议,每个客户端连接使用一个独立的Socket进行通信;对于UDP协议,客户端可以通过同一个Socket进行通信。

在IOCPServer的实现中,每一个工作线程都包含了一个消息队列,用于保存与自己相关的IO请求,同时也保存了客户端的数据接收和数据发送缓冲区。每当有新的IO事件发生时,工作线程就会从IOCP对象中获取IO请求的结果,并将其保存到自己的消息队列中。

同时,工作线程也会不断的从自己的消息队列中获取最新的IO请求,并分发给相应的业务逻辑处理函数进行处理。在这个过程中,业务逻辑处理函数可以通过事件处理器来实现数据的接收和发送。

下面是一个简单的业务逻辑处理函数的示例代码:

void HandleMessage(BOOL isTcp, SOCKET sock, BYTE* buf, DWORD len, OVERLAPPED* ol)

{

// 根据请求类型执行不同的操作

if (isTcp)

{

// TCP协议

}

else

{

// UDP协议

}

// 发送数据

m_eventLoop.PushSendDataEvent(

sock,

pSendBuf,

nSendSize,

new CMyOverlapped(SendCompleteProc),

TRUE,

pSendBuf

);

}

六、IOCPServer的性能优化

在实际应用中,为了保证IOCPServer的高效性能,需要做好以下几个方面的优化工作。

1、调整线程池大小

线程池的大小会直接影响工作线程的数量,从而影响整个IOCPServer的并发性能。如果线程池过小,不能满足高并发的请求,即导致工作线程竞争CPU资源,从而导致性能下降。如果线程池过大,则会浪费系统资源。

在实际使用中,线程池大小需要根据系统具体情况来调整。对于性能要求较高的系统,可以考虑使用线程池动态调整的方式,根据负载情况自适应调整线程池大小。

2、避免频繁的IOCP投递

在IOCP技术中,投递IO请求需要系统内核开销,如果频繁投递IO请求,会产生较大的开销,从而导致性能下降。因此,在使用IOCPServer时,应该尽量减少IOCP投递的次数,采用批量处理的方式来提高性能。

3、使用高效的数据结构

在IOCPServer的实现中,频繁使用的数据结构包括消息队列、Socket缓存和事件处理器等。对于这些数据结构,需要选择高效的数据结构和算法来优化性能。

在消息队列中,可以采用无锁队列来提高并发性能;在Socket缓存中,可以采用哈希表等数据结构来优化检索性能。同时,还应该注意对象的分配与回收,避免产生内存碎片。

七、

通过以上的介绍,我们可以了解到IOCPServer基于IOCP技术实现了高性能的异步网络通信。IOCPServer通过使用IOCP技术实现了异步IO通信,并使用线程池机制来管理工作线程,从而实现真正的异步IO操作。同时,IOCPServer使用高效的数据结构和算法来优化性能,从而支持完成大量客户端请求的并发处理。

相关问题拓展阅读:

如何提高高性能服务器并发量

1、减少内存分配和释放

服务器在运行过程中,需要大量的内存容量来支撑,内存的分配和释放就尤为关键。用户在使用服务器的时候,可以通过改善数据结构以及算法制度来减少中间临时变量的内存分配和数据复制时间。

另外,可以选择使用共享内存模式来降低内存的分配和释放瞎纯凳问题。共享内存在多处理器系统中,可以被不同的中央处理器访问,也可以有不同的进程共享,是一种非常快的进程通信方式。

2、使用持久链接

持久链接也被称为场链接,是通过TCP通信的一种方式。在一次TCP链接中持续发送多份数据而不断开连接。

从性能角度上来讲,建磨旅立TCP链接次数越少,越有利于性能的提升,尤其对于密集型图片或者网页等数据处理上来说有明显的加速作用。

3、改进I/O模型

I/O操作根据设备裤森形式有不同的类型,例如我们常见的内存I/O,网络I/O,磁盘I/O。针对网络I/O和磁盘I/O, 它们的速度要慢很多,可以选择采用高带宽网络适配器可以提高网络I/O速度。

以上的I/O操作时需要CPU来调度的,这就需要CPU空出时间来等待I/O操作。如果在CPU调度上使用时间较少,也就能节约出CPU的处理时间,从这一点上来说也是提升高服务器并发处理能力的方式。

4、改进服务器并发数策略

服务器高并发策略的调整,是为了让I/O操作和CPU计算尽量重叠进行。一方面使CPU在I/O操作时等待时间内不要空闲,另一方面也是为了更大限度缩短等待时间。【感兴趣的话点击此处,了解一下】

消除瓶颈是提高服务器性能和并发能力的唯一途径。如果你能够消除所有的瓶颈,你就能够更大的发挥硬件性能,让系统的性能和并发数到达更佳。采用多线程多雀搭核编程,使用事件驱动或异步消息机制,尽量减少阻塞和等待操作(如I/O阻塞、同步等待或计时/超时等)。原理:1、多线程多核编程,消除cpu瓶颈。2、采用IOCP或epoll,利用状态监测和通知方式,消除网络I/O阻塞瓶颈。3、采用事件驱动或异步消息机制,可以消除不必要的等待操作。4、如果是Linux,可以采用AIO来消除磁盘I/O阻塞瓶颈。5、在事件驱动框架或异步消息中统一处理timer事件,变同步为异步,而且可以顷备拿在一个线程处理无数timer事件。6、深入分析外部的阻塞来源,消除它。 比如数据库查询较慢,导致服务器处理较慢,并发数上不去,这时就要优化数据库性能。7、如果与某个其他server通信量很大,导致性能下降较多。 可以考虑把这两个server放在一个主机上,采用共享内存的方式来做IPC通信滚扮,可以大大提高性能。

IOCP怎么正确关闭socket

如果服务端的Socket比客户端的Socket先关闭,会导致客户端出现TIME_WAIT状态,占用系统资源。

所以,必须等客户端先关闭Socket后,服务器端再关闭Socket才能避免TIME_WAIT状态的出现。

判断客户端Socket的关闭

最近试验发现,当客户端Socket关闭时,服务端的Socket会接收到0字节的通知。

private int Receive(StringBuilder )

{

int read = 0, total = 0;

if (_Client != null)

{

try

{

byte bytes = new byte;

int available = _Client.Available;

do

{

read = _Client.Receive(bytes);//如果客户端Socket关闭,_Client会接受到read=0

total += read;

if (read > 0)

.Append(_Server.DefaultEncoding.GetString(bytes, 0, read));

} while (read > 0 && total 0)

{

Console.WriteLine(“Receive:” + total + “======================================”);

Console.WriteLine(.ToString());

}

return total;

}

利用0字节接收条件判断客户端Socket的关闭,开始执行服务端Socket关闭代码。

private void ThreadHandler()

{

if (_Server.TraceInConsole)

Console.WriteLine(“Begin HttpRequest…”);

try

{

while (true)

{

StringBuilder = new StringBuilder();

int receive = Receive();

if (receive > 0)

{

_Server.ReadRequest(this, .ToString());

_Server.Response(this);

_Server.ResponseFinished(this);

}

else

{

TryCloseSocket();

}

if (_Client == null)

break;

}

}

catch (Exception ex)

{

if (_Server.TraceInConsole)

Console.WriteLine(ex.Message);

}

if (_Server.TraceInConsole)

Console.WriteLine(”

www.hbbz08.com

End HttpRequest.”);

}

服务端Socket的关闭

如果直接调用Socket的Close方法会关闭得太快,可能导致客户端TIME_WAIT现象;而Thead.Sleep延时再调用Socket的Close方法也不理想。应该采用尝试向客户端发送数据,然后利用异常来关闭Socket,方法如下。

private void TryCloseSocket()

{

try

{

while (true)

{

Thread.Sleep(1500);

Send(HttpServer.BYTES_CRLF); //发送自定义的字节,如果客户端关闭出现SocketException,然后关闭服务端Socket

if (_Client == null)

break;

}

}

catch (SocketException)

{

CloseSocket();

}

}

private void CloseSocket()

{

if (_Client != null)

{

_Client.Shutdown(SocketShutdown.Both);

_Client.Close();

_Client = null;

if (_Server.TraceInConsole)

{

Console.WriteLine(“Close socket.”);

}

}

}

mfc 多线程问题

问题描述不明确,二楼不错,长知识了。

在windows下做服务器更好的方案是IOCP(I/O Complete port),中文名I/O完成端口

性能很不错。涉及windows高级编程,难学指数比较高

你的的感觉很不错,这个方案不可行:

1.会浪费大量CPU时间。一台计算机CPU个数有限,如果你的计算机只有2个CPU,却开了200线程。这个时候在同一时间,最多有2个线程在运行(因为你只有2个CPU),但是线程的不断切换让你感觉好像200个都在运行,只不过速度很慢。(此时线程切换会耗掉大量CPU时间,得不偿失)。

2.浪费内存。线程在windows中需要用数据表示,200个线程,开销有点浪费(虽然现在内存都很大,但是我们不能浪费)

3.线程同步问题会让你晕掉的,200个线程并发处理是很麻烦的早源,要进行线程同步,以及线程通信,同步和通信是多线程芦饥必须深思熟虑的。

4.有一个很不错的陪睁返解决方案—IOCP

关于IOCP的学习,网上资料很多在此不多言。

enjoy coding

使用SuspendThread()和ResumeThread()函数,可以挂起和唤醒一个线程,调用这铅陵两个函数的可以是其他线程,也可以是本身。

睡眠也就是楼上说的Sleep()函槐枝戚数或SleepEx函数,这个只是暂时挂起线程一段指定的事件,用于线程和用户交互。当然,休眠也就是挂起了,这个挂起时间是不确定的,是需要ResumeThread()的。

说到底,休眠和睡眠都是挂起搭慎,只是时间确不确定和需不需要唤醒的问题。休眠是需要有线程唤醒的,睡眠自己的时间到了就自己醒了,这就是区别!

iocp服务器源码的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于iocp服务器源码,详解IOCPServer源码实现原理,如何提高高性能服务器并发量,IOCP怎么正确关闭socket,mfc 多线程问题的信息别忘了在本站进行查找喔。


数据运维技术 » 详解IOCPServer源码实现原理 (iocp服务器源码)