(IOCP)-C#高性能Socket服务器的实现

C#高性能Socket服务器的实现(IOCP)

https://www.jianshu.com/p/c65c0eb59f22

引言

我一直在探寻一个高性能的Socket客户端代码。以前,我使用Socket类写了一些基于传统异步编程模型的代码(BeginSend、BeginReceive,等等)也看过很多博客的知识,在linux中有poll和epoll来实现,在windows下面

微软MSDN中也提供了SocketAsyncEventArgs这个类来实现IOCP 地址:https://msdn.microsoft.com/zh-cn/library/system.net.sockets.socketasynceventargs.aspx

NET Framework中的APM也称为Begin/End模式。这是因为会调用Begin方法来启动异步操作,然后返回一个IAsyncResult 对象。可以选择将一个代理作为参数提供给Begin方法,异步操作完成时会调用该方法。或者,一个线程可以等待 IAsyncResult.AsyncWaitHandle。当回调被调用或发出等待信号时,就会调用End方法来获取异步操作的结果。这种模式很灵活,使用相对简单,在 .NET Framework 中非常常见。

但是,您必须注意,如果进行大量异步套接字操作,是要付出代价的。针对每次操作,都必须创建一个IAsyncResult对象,而且该对象不能被重复使用。由于大量使用对象分配和垃圾收集,这会影响性能。为了解决这个问题,新版本提供了另一个使用套接字上执行异步I/O的方法模式。这种新模式并不要求为每个套接字操作分配操作上下文对象。

代码下载:http://download.csdn.net/detail/zhujunxxxxx/8431289这里的代码优化了的

目标

在上面微软提供的例子我觉得不是很完整,没有具体一个流程,只是受到客户端消息后发送相同内容给客户端,初学者不容易看懂流程,因为我花了一天的时间来实现一个功能齐全的IOCP服务器,

效果如下

代码

首先是ICOPServer.cs 这个类是IOCP服务器的核心类,目前这个类是网络上比较全的代码,MSDN上面的例子都没有我的全

using?System;??

using?System.Collections.Generic;??

using?System.Linq;??

using?System.Text;??

using?System.Net.Sockets;??

using?System.Net;??

using?System.Threading;??

namespace?ServerTest??

{??

///???

///?IOCP?SOCKET服务器??

///???

public?class?IOCPServer?:?IDisposable??

????{??

const?int?opsToPreAlloc?=?2;??

????????#region?Fields??

///???

///?服务器程序允许的最大客户端连接数??

///???

private?int?_maxClient;??

///???

///?监听Socket,用于接受客户端的连接请求??

///???

private?Socket?_serverSock;??

///???

///?当前的连接的客户端数??

///???

private?int?_clientCount;??

///???

///?用于每个I/O?Socket操作的缓冲区大小??

///???

private?int?_bufferSize?=?1024;??

///???

///?信号量??

///???

????????Semaphore?_maxAcceptedClients;??

///???

///?缓冲区管理??

///???

????????BufferManager?_bufferManager;??

///???

///?对象池??

///???

????????SocketAsyncEventArgsPool?_objectPool;??

private?bool?disposed?=?false;??

????????#endregion??

????????#region?Properties??

///???

///?服务器是否正在运行??

///???

public?bool?IsRunning?{?get;?private?set;?}??

///???

///?监听的IP地址??

///???

public?IPAddress?Address?{?get;?private?set;?}??

///???

///?监听的端口??

///???

public?int?Port?{?get;?private?set;?}??

///???

///?通信使用的编码??

///???

public?Encoding?Encoding?{?get;?set;?}??

????????#endregion??

????????#region?Ctors??

///???

///?异步IOCP?SOCKET服务器??

///???

///?监听的端口??

///?最大的客户端数量??

public?IOCPServer(int?listenPort,int?maxClient)??

:this(IPAddress.Any,?listenPort,?maxClient)??

????????{??

????????}??

///???

///?异步Socket?TCP服务器??

///???

///?监听的终结点??

///?最大客户端数量??

public?IOCPServer(IPEndPoint?localEP,?int?maxClient)??

:this(localEP.Address,?localEP.Port,maxClient)??

????????{??

????????}??

///???

///?异步Socket?TCP服务器??

///???

///?监听的IP地址??

///?监听的端口??

///?最大客户端数量??

public?IOCPServer(IPAddress?localIPAddress,?int?listenPort,?int?maxClient)??

????????{??

this.Address?=?localIPAddress;??

this.Port?=?listenPort;??

this.Encoding?=?Encoding.Default;??

????????????_maxClient?=?maxClient;??

_serverSock?=new?Socket(localIPAddress.AddressFamily,?SocketType.Stream,?ProtocolType.Tcp);??

_bufferManager?=new?BufferManager(_bufferSize?*?_maxClient?*?opsToPreAlloc,_bufferSize);??

_objectPool?=new?SocketAsyncEventArgsPool(_maxClient);??

_maxAcceptedClients?=new?Semaphore(_maxClient,?_maxClient);???

????????}??

????????#endregion??

????????#region?初始化??

///???

///?初始化函数??

///???

public?void?Init()??

????????{??

//?Allocates?one?large?byte?buffer?which?all?I/O?operations?use?a?piece?of.??This?gaurds???

//?against?memory?fragmentation??

????????????_bufferManager.InitBuffer();??

//?preallocate?pool?of?SocketAsyncEventArgs?objects??

????????????SocketAsyncEventArgs?readWriteEventArg;??

for?(int?i?=?0;?i?<?_maxClient;?i++)??

????????????{??

//Pre-allocate?a?set?of?reusable?SocketAsyncEventArgs??

readWriteEventArg?=new?SocketAsyncEventArgs();??

readWriteEventArg.Completed?+=new?EventHandler(OnIOCompleted);??

readWriteEventArg.UserToken?=null;??

//?assign?a?byte?buffer?from?the?buffer?pool?to?the?SocketAsyncEventArg?object??

????????????????_bufferManager.SetBuffer(readWriteEventArg);??

//?add?SocketAsyncEventArg?to?the?pool??

????????????????_objectPool.Push(readWriteEventArg);??

????????????}??

????????}??

????????#endregion??

????????#region?Start??

///???

///?启动??

///???

public?void?Start()??

????????{??

if?(!IsRunning)??

????????????{??

????????????????Init();??

IsRunning?=true;??

IPEndPoint?localEndPoint?=new?IPEndPoint(Address,?Port);??

//?创建监听socket??

_serverSock?=new?Socket(localEndPoint.AddressFamily,?SocketType.Stream,?ProtocolType.Tcp);??

//_serverSock.ReceiveBufferSize?=?_bufferSize;??

//_serverSock.SendBufferSize?=?_bufferSize;??

if?(localEndPoint.AddressFamily?==?AddressFamily.InterNetworkV6)??

????????????????{??

//?配置监听socket为?dual-mode?(IPv4?&?IPv6)???

//?27?is?equivalent?to?IPV6_V6ONLY?socket?option?in?the?winsock?snippet?below,??

_serverSock.SetSocketOption(SocketOptionLevel.IPv6,?(SocketOptionName)27,false);??

_serverSock.Bind(new?IPEndPoint(IPAddress.IPv6Any,?localEndPoint.Port));??

????????????????}??

else??

????????????????{??

????????????????????_serverSock.Bind(localEndPoint);??

????????????????}??

//?开始监听??

_serverSock.Listen(this._maxClient);??

//?在监听Socket上投递一个接受请求。??

StartAccept(null);??

????????????}??

????????}??

????????#endregion??

????????#region?Stop??

///???

///?停止服务??

///???

public?void?Stop()??

????????{??

if?(IsRunning)??

????????????{??

IsRunning?=false;??

????????????????_serverSock.Close();??

//TODO?关闭对所有客户端的连接??

????????????}??

????????}??

????????#endregion??

????????#region?Accept??

///???

///?从客户端开始接受一个连接操作??

///???

private?void?StartAccept(SocketAsyncEventArgs?asyniar)??

????????{??

if?(asyniar?==?null)??

????????????{??

asyniar?=new?SocketAsyncEventArgs();??

asyniar.Completed?+=new?EventHandler(OnAcceptCompleted);??

????????????}??

else??

????????????{??

//socket?must?be?cleared?since?the?context?object?is?being?reused??

asyniar.AcceptSocket?=null;??

????????????}??

????????????_maxAcceptedClients.WaitOne();??

if?(!_serverSock.AcceptAsync(asyniar))??

????????????{??

????????????????ProcessAccept(asyniar);??

//如果I/O挂起等待异步则触发AcceptAsyn_Asyn_Completed事件??

//此时I/O操作同步完成,不会触发Asyn_Completed事件,所以指定BeginAccept()方法??

????????????}??

????????}??

///???

///?accept?操作完成时回调函数??

///???

///?Object?who?raised?the?event.??

///?SocketAsyncEventArg?associated?with?the?completed?accept?operation.??

private?void?OnAcceptCompleted(object?sender,?SocketAsyncEventArgs?e)??

????????{??

????????????ProcessAccept(e);??

????????}??

///???

///?监听Socket接受处理??

///???

///?SocketAsyncEventArg?associated?with?the?completed?accept?operation.??

private?void?ProcessAccept(SocketAsyncEventArgs?e)??

????????{??

if?(e.SocketError?==?SocketError.Success)??

????????????{??

Socket?s?=?e.AcceptSocket;//和客户端关联的socket??

if?(s.Connected)??

????????????????{??

try??

????????????????????{??

Interlocked.Increment(ref?_clientCount);//原子操作加1??

????????????????????????SocketAsyncEventArgs?asyniar?=?_objectPool.Pop();??

????????????????????????asyniar.UserToken?=?s;??

Log4Debug(String.Format("客户?{0}?连入,?共有?{1}?个连接。",?s.RemoteEndPoint.ToString(),?_clientCount));??

if?(!s.ReceiveAsync(asyniar))//投递接收请求??

????????????????????????{??

????????????????????????????ProcessReceive(asyniar);??

????????????????????????}??

????????????????????}??

catch?(SocketException?ex)??

????????????????????{??

Log4Debug(String.Format("接收客户?{0}?数据出错,?异常信息:?{1}?。",?s.RemoteEndPoint,?ex.ToString()));??

//TODO?异常处理??

????????????????????}??

//投递下一个接受请求??

????????????????????StartAccept(e);??

????????????????}??

????????????}??

????????}??

????????#endregion??

????????#region?发送数据??

///???

///?异步的发送数据??

///???

///???

///???

public?void?Send(SocketAsyncEventArgs?e,?byte[]?data)??

????????{??

if?(e.SocketError?==?SocketError.Success)??

????????????{??

Socket?s?=?e.AcceptSocket;//和客户端关联的socket??

if?(s.Connected)??

????????????????{??

Array.Copy(data,?0,?e.Buffer,?0,?data.Length);//设置发送数据??

//e.SetBuffer(data,?0,?data.Length);?//设置发送数据??

if?(!s.SendAsync(e))//投递发送请求,这个函数有可能同步发送出去,这时返回false,并且不会引发SocketAsyncEventArgs.Completed事件??

????????????????????{??

//?同步发送时处理发送完成事件??

????????????????????????ProcessSend(e);??

????????????????????}??

else??

????????????????????{??

????????????????????????CloseClientSocket(e);??

????????????????????}??

????????????????}??

????????????}??

????????}??

///???

///?同步的使用socket发送数据??

///???

///???

///???

///???

///???

///???

public?void?Send(Socket?socket,?byte[]?buffer,?int?offset,?int?size,?int?timeout)??

????????{??

????????????socket.SendTimeout?=?0;??

int?startTickCount?=?Environment.TickCount;??

int?sent?=?0;?//?how?many?bytes?is?already?sent??

do??

????????????{??

if?(Environment.TickCount?>?startTickCount?+?timeout)??

????????????????{??

//throw?new?Exception("Timeout.");??

????????????????}??

try??

????????????????{??

????????????????????sent?+=?socket.Send(buffer,?offset?+?sent,?size?-?sent,?SocketFlags.None);??

????????????????}??

catch?(SocketException?ex)??

????????????????{??

if?(ex.SocketErrorCode?==?SocketError.WouldBlock?||??

????????????????????ex.SocketErrorCode?==?SocketError.IOPending?||??

????????????????????ex.SocketErrorCode?==?SocketError.NoBufferSpaceAvailable)??

????????????????????{??

//?socket?buffer?is?probably?full,?wait?and?try?again??

????????????????????????Thread.Sleep(30);??

????????????????????}??

else??

????????????????????{??

throw?ex;?//?any?serious?error?occurr??

????????????????????}??

????????????????}??

}while?(sent?<?size);??

????????}??

///???

///?发送完成时处理函数??

///???

///?与发送完成操作相关联的SocketAsyncEventArg对象??

private?void?ProcessSend(SocketAsyncEventArgs?e)??

????????{??

if?(e.SocketError?==?SocketError.Success)??

????????????{??

????????????????Socket?s?=?(Socket)e.UserToken;??

//TODO??

????????????}??

else??

????????????{??

????????????????CloseClientSocket(e);??

????????????}??

????????}??

????????#endregion??

????????#region?接收数据??

///???

///接收完成时处理函数??

///???

///?与接收完成操作相关联的SocketAsyncEventArg对象??

private?void?ProcessReceive(SocketAsyncEventArgs?e)??

????????{??

if?(e.SocketError?==?SocketError.Success)//if?(e.BytesTransferred?>?0?&&?e.SocketError?==?SocketError.Success)??

????????????{??

//?检查远程主机是否关闭连接??

if?(e.BytesTransferred?>?0)??

????????????????{??

????????????????????Socket?s?=?(Socket)e.UserToken;??

//判断所有需接收的数据是否已经完成??

if?(s.Available?==?0)??

????????????????????{??

//从侦听者获取接收到的消息。???

//String?received?=?Encoding.ASCII.GetString(e.Buffer,?e.Offset,?e.BytesTransferred);??

//echo?the?data?received?back?to?the?client??

//e.SetBuffer(e.Offset,?e.BytesTransferred);??

byte[]?data?=?new?byte[e.BytesTransferred];??

Array.Copy(e.Buffer,?e.Offset,?data,?0,?data.Length);//从e.Buffer块中复制数据出来,保证它可重用??

string?info=Encoding.Default.GetString(data);??

Log4Debug(String.Format("收到?{0}?数据为?{1}",s.RemoteEndPoint.ToString(),info));??

//TODO?处理数据??

//增加服务器接收的总字节数。??

????????????????????}??

if?(!s.ReceiveAsync(e))//为接收下一段数据,投递接收请求,这个函数有可能同步完成,这时返回false,并且不会引发SocketAsyncEventArgs.Completed事件??

????????????????????{??

//同步接收时处理接收完成事件??

????????????????????????ProcessReceive(e);??

????????????????????}??

????????????????}??

????????????}??

else??

????????????{??

????????????????CloseClientSocket(e);??

????????????}??

????????}??

????????#endregion??

????????#region?回调函数??

///???

///?当Socket上的发送或接收请求被完成时,调用此函数??

///???

///?激发事件的对象??

///?与发送或接收完成操作相关联的SocketAsyncEventArg对象??

private?void?OnIOCompleted(object?sender,?SocketAsyncEventArgs?e)??

????????{??

//?Determine?which?type?of?operation?just?completed?and?call?the?associated?handler.??

switch?(e.LastOperation)??

????????????{??

case?SocketAsyncOperation.Accept:??

????????????????????ProcessAccept(e);??

break;??

case?SocketAsyncOperation.Receive:??

????????????????????ProcessReceive(e);??

break;??

default:??

throw?new?ArgumentException("The?last?operation?completed?on?the?socket?was?not?a?receive?or?send");??

????????????}??

????????}??

????????#endregion??

????????#region?Close??

///???

///?关闭socket连接??

///???

///?SocketAsyncEventArg?associated?with?the?completed?send/receive?operation.??

private?void?CloseClientSocket(SocketAsyncEventArgs?e)??

????????{??

Log4Debug(String.Format("客户?{0}?断开连接!",((Socket)e.UserToken).RemoteEndPoint.ToString()));??

Socket?s?=?e.UserTokenas?Socket;??

????????????CloseClientSocket(s,?e);??

????????}??

///???

///?关闭socket连接??

///???

///???

///???

private?void?CloseClientSocket(Socket?s,?SocketAsyncEventArgs?e)??

????????{??

try??

????????????{??

????????????????s.Shutdown(SocketShutdown.Send);??

????????????}??

catch?(Exception)??

????????????{??

//?Throw?if?client?has?closed,?so?it?is?not?necessary?to?catch.??

????????????}??

finally??

????????????{??

????????????????s.Close();??

????????????}??

Interlocked.Decrement(ref?_clientCount);??

????????????_maxAcceptedClients.Release();??

_objectPool.Push(e);//SocketAsyncEventArg?对象被释放,压入可重用队列。??

????????}??

????????#endregion??

????????#region?Dispose??

///???

///?Performs?application-defined?tasks?associated?with?freeing,???

///?releasing,?or?resetting?unmanaged?resources.??

///???

public?void?Dispose()??

????????{??

Dispose(true);??

GC.SuppressFinalize(this);??

????????}??

///???

///?Releases?unmanaged?and?-?optionally?-?managed?resources??

///???

///?true?to?release???

///?both?managed?and?unmanaged?resources;?false???

///?to?release?only?unmanaged?resources.??

protected?virtual?void?Dispose(bool?disposing)??

????????{??

if?(!this.disposed)??

????????????{??

if?(disposing)??

????????????????{??

try??

????????????????????{??

????????????????????????Stop();??

if?(_serverSock?!=?null)??

????????????????????????{??

_serverSock?=null;??

????????????????????????}??

????????????????????}??

catch?(SocketException?ex)??

????????????????????{??

//TODO?事件??

????????????????????}??

????????????????}??

disposed?=true;??

????????????}??

????????}??

????????#endregion??

public?void?Log4Debug(string?msg)??

????????{??

Console.WriteLine("notice:"+msg);??

????????}??

????}??

}

原文地址:https://www.cnblogs.com/Leo_wl/p/9920851.html

时间: 2024-10-01 07:57:59

(IOCP)-C#高性能Socket服务器的实现的相关文章

C#高性能Socket服务器SocketAsyncEventArgs的实现(IOCP)

原创性申明 本文作者:小竹zz  博客地址:http://blog.csdn.net/zhujunxxxxx/article/details/43573879转载请注明出处 引言 我一直在探寻一个高性能的Socket客户端代码.以前,我使用Socket类写了一些基于传统异步编程模型的代码(BeginSend.BeginReceive,等等)也看过很多博客的知识,在linux中有poll和epoll来实现,在windows下面 微软MSDN中也提供了SocketAsyncEventArgs这个类来

高性能 Socket 组件 HP-Socket v3.2.1 正式发布

HP-Socket 是一套通用的高性能 TCP/UDP Socket 组件,包含服务端组件.客户端组件和 Agent 组件,广泛适用于各种不同应用场景的 TCP/UDP 通信系统,提供 C/C++.C#.Delphi.E(易语言).Java.Python 等编程语言接口.HP-Socket 对通信层实现完全封装,上层应用不必关注通信层的任何细节:HP-Socket 提供基于事件通知模型的 API 接口,能非常简单高效地整合到新旧应用程序中.为了让使用者能方便快速地学习和使用 HP-Socket,

高性能 Socket 组件 HP-Socket v3.2.1-RC4 公布

HP-Socket 是一套通用的高性能 TCP/UDP Socket 组件,包括服务端组件.client组件和 Agent 组件,广泛适用于各种不同应用场景的 TCP/UDP 通信系统,提供 C/C++.C#.Delphi.E.Java 等编程语言开发接口.HP-Socket 对通信层实现全然封装,上层应用不必关注通信层的不论什么细节:HP-Socket 提供基于事件通知模型的 API 接口,能很easy高效地整合到新旧应用程序中.为了让使用者能方便高速地学习和使用 HP-Socket,迅速掌握

高性能 Socket 组件 HP-Socket v3.2.1-RC4 发布

HP-Socket 是一套通用的高性能 TCP/UDP Socket 组件,包含服务端组件.客户端组件和 Agent 组件,广泛适用于各种不同应用场景的 TCP/UDP 通信系统,提供 C/C++.C#.Delphi.E.Java 等编程语言开发接口.HP-Socket 对通信层实现完全封装,上层应用不必关注通信层的任何细节:HP-Socket 提供基于事件通知模型的 API 接口,能非常简单高效地整合到新旧应用程序中.为了让使用者能方便快速地学习和使用 HP-Socket,迅速掌握组件的设计思

基于JDK7 NIO2的高性能web服务器实践之二(转)

前一篇博客,我简单提了下怎么为NIO2增加TransmitFile支持,文件传送吞吐量是一个性能关注点,此外,并发连接数也是重要的关注点. 不过JDK7中又一次做了简单的实现,不支持同时投递多个AcceptEx请求,只支持一次一个,返回后再投递.这样,客户端连接的接受速度必然大打折扣.不知道为什么sun会做这样的实现,WSASend()/WSAReceive()一次只允许一个还是可以理解,毕竟简化了编程,不用考虑封包乱序问题.也降低了内存耗尽的风险.AcceptEx却没有这样的理由了. 于是再一

高性能 Socket 组件 HP-Socket v3.2.1-RC5 公布

HP-Socket 是一套通用的高性能 TCP/UDP Socket 组件,包括服务端组件.client组件和 Agent 组件,广泛适用于各种不同应用场景的 TCP/UDP 通信系统,提供 C/C++.C#.Delphi.E.Java 等编程语言开发接口.HP-Socket 对通信层实现全然封装,上层应用不必关注通信层的不论什么细节:HP-Socket 提供基于事件通知模型的 API 接口,能很easy高效地整合到新旧应用程序中.为了让使用者能方便高速地学习和使用 HP-Socket,迅速掌握

PHP socket 服务器框架集

1.Swoole:重新定义PHP PHP语言的高性能网络通信框架,提供了PHP语言的异步多线程服务器,异步TCP/UDP网络客户端,异步MySQL,数据库连接池,AsyncTask,消息队列,毫秒定时器,异步文件读写,异步DNS查询.Swoole可以广泛应用于互联网.移动通信.企业软件.网络游戏.物联网.车联网.智能家庭等领域. 使用PHP+Swoole作为网络通信框架,可以使企业IT研发团队的效率大大提升,更加专注于开发创新产品. 2.workerman workerman是一个高性能的PHP

&lt;摘录&gt;详谈高性能TCP服务器的开发

对于开发一款高性能服务器程序,广大服务器开发人员在一直为之奋斗和努力.其中一个影响服务器的重要瓶颈就是服务器的网络处理模块.如果一款服务器程序不能及时的处理用户的数据.则服务器的上层业务逻辑再高效也是徒劳.所以一个服务器程序的网络处理能力直接影响到整个服务器的性能, 本文主要介绍在windows平台下开发高性能的网络处理模块以及自己在设计开发服务器网络模块遇到的一些问题和开发心得.本篇主要介绍TCP服务器的设计, 下一篇将主要介绍UDP服务器的设计. 众所周知, 对于服务器来说windows下网

CentOS 5.5下安装mysql5.1.57+php5.2.17(FastCGI)+nginx1.0.1高性能Web服务器 [转载]

CentOS 5.5下安装mysql5.1.57+php5.2.17(FastCGI)+nginx1.0.1高性能Web服务器 [转载] 2012年09月05日 ⁄ Linux技术 ⁄ 共 12362字 ⁄ 字号 小 中 大 ⁄ 暂无评论 ⁄ 阅读 85 views 次 由于生产环境都是freebsd平台,之前也写了一篇FreeBSD下安装 mysql5.1.56+php5.2.17(FastCGI)+nginx1.0.1高性能Web服务器,有童鞋想要帮忙写一篇关于centos下的安 装教程,其