windows上 支持IOCP 的libevent TCP服务器该怎么个写法

windows上 支持IOCP 的libevent TCP服务器该怎么个写法,第1张

event_base_get_method函数能够获取对应的event_base使用的是哪个后端(即select、IOCP这些函数)。该函数返回一个字符串,字符串的内容就是select、poll、iocp这些后端的名字。 更正一下,由于在WIndows中,event_base_get_method函数返回的是win...

是tcp的

服务器核心代码 AsyncServer.cs

/// <summary>

/// 异步SOCKET 服务器

/// </summary>

public class AsyncServer : IDisposable

{

#region Fields

/// <summary>

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

/// </summary>

private int _maxClient

/// <summary>

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

/// </summary>

private int _clientCount

/// <summary>

/// 服务器使用的异步socket

/// </summary>

private Socket _serverSock

/// <summary>

/// 客户端会话列表

/// </summary>

private List<session>_clients

private bool disposed = false

#endregion

#region Properties

/// <summary>

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

/// </summary>

public bool IsRunning { getprivate set}

/// <summary>

/// 监听的IP地址

/// </summary>

public IPAddress Address { getprivate set}

/// <summary>

/// 监听的端口

/// </summary>

public int Port { getprivate set}

/// <summary>

/// 通信使用的编码

/// </summary>

public Encoding Encoding { getset}

#endregion

#region Ctors

/// <summary>

/// 异步Socket TCP服务器

/// </summary>

///<param name="listenPort">监听的端口

public AsyncServer(int listenPort)

: this(IPAddress.Any, listenPort,1024)

{

}

/// <summary>

/// 异步Socket TCP服务器

/// </summary>

///<param name="localEP">监听的终结点

public AsyncServer(IPEndPoint localEP)

: this(localEP.Address, localEP.Port,1024)

{

}

/// <summary>

/// 异步Socket TCP服务器

/// </summary>

///<param name="localIPAddress">监听的IP地址

///<param name="listenPort">监听的端口

///<param name="maxClient">最大客户端数量

public AsyncServer(IPAddress localIPAddress, int listenPort,int maxClient)

{

this.Address = localIPAddress

this.Port = listenPort

this.Encoding = Encoding.Default

_maxClient = maxClient

_clients = new List<session>()

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

}

#endregion

#region Server

/// <summary>

/// 启动服务器

/// </summary>

/// <returns>异步TCP服务器</returns>

public AsyncServer Start()

{

if (!IsRunning)

{

IsRunning = true

_serverSock.Bind(new IPEndPoint(this.Address, this.Port))

_serverSock.Listen(1024)

_serverSock.BeginAccept(new AsyncCallback(HandleAcceptConnected), _serverSock)

}

return this

}

/// <summary>

/// 启动服务器

/// </summary>

///<param name="backlog">

/// 服务器所允许的挂起连接序列的最大长度

///

/// <returns>异步TCP服务器</returns>

public AsyncServer Start(int backlog)

{

if (!IsRunning)

{

IsRunning = true

_serverSock.Bind(new IPEndPoint(this.Address, this.Port))

_serverSock.Listen(backlog)

_serverSock.BeginAccept(new AsyncCallback(HandleAcceptConnected), _serverSock)

}

return this

}

/// <summary>

/// 停止服务器

/// </summary>

/// <returns>异步TCP服务器</returns>

public AsyncServer Stop()

{

if (IsRunning)

{

IsRunning = false

_serverSock.Close()

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

}

return this

}

#endregion

#region Receive

/// <summary>

/// 处理客户端连接

/// </summary>

///<param name="ar">

private void HandleAcceptConnected(IAsyncResult ar)

{

if (IsRunning)

{

Socket server = (Socket)ar.AsyncState

Socket client = server.EndAccept(ar)

//检查是否达到最大的允许的客户端数目

if (_clientCount == _maxClient)

{

//TODO 触发事件

RaiseServerException(null)

}

else

{

Session session = new Session(client)

lock (_clients)

{

_clients.Add(session)

_clientCount++

RaiseClientConnected(session)//触发客户端连接事件

}

session.RecvDataBuffer = new byte[client.ReceiveBufferSize]

//开始接受来自该客户端的数据

client.BeginReceive(session.RecvDataBuffer, 0, session.RecvDataBuffer.Length, SocketFlags.None,

new AsyncCallback(HandleDataReceived), session)

}

//接受下一个请求

server.BeginAccept(new AsyncCallback(HandleAcceptConnected), ar.AsyncState)

}

}

/// <summary>

/// 处理客户端数据

/// </summary>

///<param name="ar">

private void HandleDataReceived(IAsyncResult ar)

{

if (IsRunning)

{

Session session = (Session)ar.AsyncState

Socket client = session.ClientSocket

try

{

//如果两次开始了异步的接收,所以当客户端退出的时候

//会两次执行EndReceive

int recv = client.EndReceive(ar)

if (recv == 0)

{

//TODO 触发事件 (关闭客户端)

CloseSession(session)

RaiseNetError(session)

return

}

//TODO 处理已经读取的数据 ps:数据在session的RecvDataBuffer中

RaiseDataReceived(session)

//TODO 触发数据接收事件

}

catch (SocketException ex)

{

//TODO 异常处理

RaiseNetError(session)

}

finally

{

//继续接收来自来客户端的数据

client.BeginReceive(session.RecvDataBuffer, 0, session.RecvDataBuffer.Length, SocketFlags.None,

new AsyncCallback(HandleDataReceived), session)

}

}

}

#endregion

看到一些资料,说Windows的IOCP后发制人,比Linux的epoll优越很多。那么优势到底在哪里?如何选择Linux或Windows作为服务器呢?

也看到有资料说,同样在Linux上,使用reactor机制的网络库性能比使用Proactor机制的Asio性能好接近1/5,这个例子可能与题目无关,不过我在文中可能会做一些相关的分析。

系统I/O模型 可分为三类:

IOCP基于非阻塞异步模型,而epoll基于非阻塞同步模型。

参考 Hyunjik Bae, A game programmer since 1995 说的:

参考[4]比较了Windows IOCP和Linux epoll的性能,结论是如果使用Linux,应该使用支持RSS(multi-queue)的NIC,这样可以达到与IOCP类似的性能。

Boost.Asio为了兼容Windows和Linux,在Linux上用epoll和select去模拟proactor模式,影响了它的效率和实现复杂度。其效率不及使用原生I/O机制的其它实现为Reactor模式的网络库。

引用来自参考[3]的话:

[1] Why doesn't Linux have a system like IOCP or Rio does? , 2014.

[2] 两种高性能I/O设计模式(Reactor/Proactor)的比较 - 文章 - 伯乐在线

[3] Practical difference between epoll and Windows IO Completion Ports (IOCP)

[4] Windows IOCP vs Linux EPOLL Performance Comparison


欢迎分享,转载请注明来源:夏雨云

原文地址:https://www.xiayuyun.com/zonghe/264665.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-04-17
下一篇2023-04-17

发表评论

登录后才能评论

评论列表(0条)

    保存