VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > 编程开发 > c#编程 >
  • 高性能服务器架构(Reactor、Proactor)

第13章 高性能服务器架构
13.1 高性能服务器架构(Reactor、Proactor)
一、为什么要学架构?我踩过的“代码失控”坑
刚用SocketAsyncEventArgs写IOCP服务器时,代码写得一团糟——IO事件处理、业务逻辑、连接管理混在一起,改个业务逻辑都要改IO代码,上线后bug不断。后来才发现,我需要用架构模式把代码分层,让IO、业务、连接管理各司其职。这节我把自己从“面条代码”到“架构化代码”的经验揉进去,用大白话讲透Reactor、Proactor这两种高性能服务器架构,结合C#代码逐行讲解,让你写的服务器代码既高性能又易维护。
二、先搞懂架构的本质:把代码“模块化”
架构模式是一套经过验证的代码组织方式,就像盖房子的图纸——按照图纸盖房子,房子既结实又好看,还容易装修。高性能服务器架构的核心是把IO操作、业务逻辑、连接管理分开,让每个模块只做一件事,提高代码的可维护性和性能。
类比:Reactor/Proactor架构就像餐厅的“后厨流程”——服务员(IO线程)负责接订单(IO事件),厨师(业务线程)负责做菜(业务逻辑),传菜员(调度线程)负责把订单传给厨师、把菜传给服务员——每个岗位只做一件事,效率高,还不容易出错。
三、Reactor架构:“事件驱动”的高性能架构
Reactor是事件驱动的架构,核心是“等待事件,处理事件”——服务器先注册需要监听的事件(比如连接事件、读事件、写事件),然后等待事件发生,事件发生后再处理。
类比:Reactor架构就像医院的“分诊台”——分诊台(Reactor)先注册需要处理的病人类型(事件),比如发烧、感冒、外伤,然后等待病人来(事件发生),病人来后分诊台把病人分到对应的科室(处理事件)。

  1. Reactor架构的核心组件
    1.Reactor(反应器):负责监听事件(比如连接事件、读事件、写事件),事件发生后分发给对应的Handler处理;
    2.Handler(处理器):负责处理具体的事件,比如连接Handler处理连接事件,读Handler处理读事件,写Handler处理写事件;
    3.事件多路分发器(Event Multiplexer):负责监听多个Socket的IO事件,比如Windows的IOCP、Linux的EPOLL、macOS的KQueue——这是Reactor架构的底层支撑。
  2. Reactor架构的三种模式
    单Reactor单线程:一个Reactor线程负责监听所有事件,处理所有vb.net教程C#教程python教程SQL教程access 2010教程事件——简单但性能低,适合低并发场景;
    单Reactor多线程:一个Reactor线程负责监听事件,事件发生后把业务逻辑交给线程池处理——性能较高,适合中并发场景;
    多Reactor多线程:多个Reactor线程负责监听事件,每个Reactor线程处理一部分事件,业务逻辑交给线程池处理——性能最高,适合高并发场景。
  3. C#实战:用Reactor架构实现单Reactor多线程服务器
    示例:Reactor架构的Socket服务器
    csharp
	using System;
	using System.Collections.Generic;
	using System.Net;
	using System.Net.Sockets;
	using System.Threading;
	using System.Threading.Tasks;
	
	namespace ReactorSocketServer;
	
	// Reactor架构的核心:反应器
	public class Reactor
	{
	private readonly Socket _listenerSocket;
	private readonly Thread _reactorThread;
	private readonly Dictionary<Socket, ConnectionHandler> _connections = new Dictionary<Socket, ConnectionHandler>();
	private readonly ThreadPool _businessThreadPool = new ThreadPool(10); // 业务线程池
	
	public Reactor(int port)
	{
	// 创建TCP监听Socket
	_listenerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
	_listenerSocket.Bind(new IPEndPoint(IPAddress.Any, port));
	_listenerSocket.Listen(100);
	
	// 启动Reactor线程
	_reactorThread = new Thread(ReactorLoop);
	_reactorThread.Start();
	Console.WriteLine("Reactor服务器已启动,端口" + port);
	}
	
	// Reactor主循环:监听事件,处理事件
	private void ReactorLoop()
	{
	while (true)
	{
	// 监听连接事件:用AcceptAsync发起异步IO操作
	var acceptArgs = new SocketAsyncEventArgs();
	acceptArgs.Completed += AcceptEvent_Completed;
	bool willRaiseEvent = _listenerSocket.AcceptAsync(acceptArgs);
	if (!willRaiseEvent)
	{
	ProcessAcceptEvent(acceptArgs);
	}
	
	// 这里可以监听其他事件,比如读事件、写事件
	// 为了简化,我们把读事件的监听放到ConnectionHandler里
	}
	}
	
	// 连接事件完成回调
	private void AcceptEvent_Completed(object sender, SocketAsyncEventArgs e)
	{
	ProcessAcceptEvent(e);
	}
	
	// 处理连接事件
	private void ProcessAcceptEvent(SocketAsyncEventArgs e)
	{
	Socket clientSocket = e.AcceptSocket;
	Console.WriteLine($"客户端已连接:{clientSocket.RemoteEndPoint}");
	
	// 创建连接处理器,处理该连接的读、写事件
	var connectionHandler = new ConnectionHandler(clientSocket, _businessThreadPool);
	_connections.Add(clientSocket, connectionHandler);
	
	// 启动连接处理器的读事件监听
	connectionHandler.StartRead();
	}
	}
	
	// 连接处理器:处理单个连接的读、写事件
	public class ConnectionHandler
	{
	private readonly Socket _clientSocket;
	private readonly ThreadPool _businessThreadPool;
	private readonly byte[] _buffer = new byte[1024];
	
	public ConnectionHandler(Socket clientSocket, ThreadPool businessThreadPool)
	{
	_clientSocket = clientSocket;
	_businessThreadPool = businessThreadPool;
	}
	
	// 启动读事件监听
	public void StartRead()
	{
	var readArgs = new SocketAsyncEventArgs();
	readArgs.SetBuffer(_buffer, 0, _buffer.Length);
	readArgs.Completed += ReadEvent_Completed;
	readArgs.UserToken = this;
	
	bool willRaiseEvent = _clientSocket.ReceiveAsync(readArgs);
	if (!willRaiseEvent)
	{
	ProcessReadEvent(readArgs);
	}
	}
	
	// 读事件完成回调
	private void ReadEvent_Completed(object sender, SocketAsyncEventArgs e)
	{
	ProcessReadEvent(e);
	}
	
	// 处理读事件
	private void ProcessReadEvent(SocketAsyncEventArgs e)
	{
	var handler = (ConnectionHandler)e.UserToken;
	Socket clientSocket = handler._clientSocket;
	
	// 客户端断开连接
	if (e.BytesTransferred == 0)
	{
	Console.WriteLine($"客户端已断开:{clientSocket.RemoteEndPoint}");
	clientSocket.Close();
	return;
	}
	
	// 解析客户端消息
	string message = System.Text.Encoding.UTF8.GetString(e.Buffer, e.Offset, e.BytesTransferred);
	Console.WriteLine($"收到客户端消息:{message}");
	
	// 把业务逻辑交给业务线程池处理
	_businessThreadPool.QueueUserWorkItem(state =>
	{
	// 处理业务逻辑:比如解析消息、调用服务等
	string response = $"服务器收到:{message}";
	
	// 异步发送响应给客户端
	handler.Send(response);
	});
	
	// 继续监听读事件
	handler.StartRead();
	}
	
	// 异步发送消息给客户端
	public void Send(string message)
	{
	byte[] buffer = System.Text.Encoding.UTF8.GetBytes(message);
	var sendArgs = new SocketAsyncEventArgs();
	sendArgs.SetBuffer(buffer, 0, buffer.Length);
	sendArgs.Completed += SendEvent_Completed;
	
	bool willRaiseEvent = _clientSocket.SendAsync(sendArgs);
	if (!willRaiseEvent)
	{
	ProcessSendEvent(sendArgs);
	}
	}
	
	// 写事件完成回调
	private void SendEvent_Completed(object sender, SocketAsyncEventArgs e)
	{
	ProcessSendEvent(e);
	}
	
	// 处理写事件
	private void ProcessSendEvent(SocketAsyncEventArgs e)
	{
	if (e.SocketError != SocketError.Success)
	{
	Console.WriteLine($"发送消息失败:{e.SocketError}");
	}
	}
	}
	
	// 简单的线程池实现
	public class ThreadPool
	{
	private readonly Queue<WaitCallback> _taskQueue = new Queue<WaitCallback>();
	private readonly List<Thread> _threads = new List<Thread>();
	private readonly object _lockObj = new object();
	
	public ThreadPool(int threadCount)
	{
	for (int i = 0; i < threadCount; i++)
	{
	var thread = new Thread(ThreadLoop);
	thread.IsBackground = true;
	thread.Start();
	_threads.Add(thread);
	}
	}
	
	private void ThreadLoop()
	{
	while (true)
	{
	WaitCallback task = null;
	lock (_lockObj)
	{
	if (_taskQueue.Count > 0)
	{
	task = _taskQueue.Dequeue();
	}
	}
	
	if (task != null)
	{
	task(null);
	}
	else
	{
	Thread.Sleep(10);
	}
	}
	}
	
	public void QueueUserWorkItem(WaitCallback callback)
	{
	lock (_lockObj)
	{
	_taskQueue.Enqueue(callback);
	}
	}
	}
	
	class Program
	{
	static void Main(string[] args)
	{
	var reactor = new Reactor(8080);
	Console.ReadLine();
	}
	}

代码逐行讲:
1.Reactor类:Reactor的核心,负责监听连接事件,处理连接事件,创建ConnectionHandler;
2.ConnectionHandler类:处理单个连接的读、写事件,读事件发生后把业务逻辑交给线程池处理,写事件负责发送响应;
3.ThreadPool类:简单的线程池实现,负责处理业务逻辑,避免每个业务逻辑都创建新线程;
4.事件驱动:所有IO操作都是异步的,事件发生后触发回调,Reactor只负责分发事件,不处理具体业务。
优点:
代码模块化:IO操作、业务逻辑、连接管理分开,代码易维护;
高性能:用异步IO操作,一个线程能处理成千上万个连接;
可扩展:可以轻松扩展成多Reactor多线程模式,支撑更高并发。
四、Proactor架构:“异步IO”的高性能架构
Proactor是异步IO的架构,核心是“发起异步IO操作,等待IO完成,处理结果”——服务器先发起异步IO操作,然后等待IO完成,IO完成后再处理结果。
类比:Proactor架构就像外卖平台——用户(服务器)先下单(发起异步IO操作),然后等待外卖(IO完成),外卖送到后用户再吃饭(处理结果)。

  1. Proactor架构的核心组件
    1.Proactor(前摄器):负责发起异步IO操作,等待IO完成,处理IO完成结果;
    2.Completion Handler(完成处理器):负责处理IO完成后的结果,比如读完成处理器处理读操作的结果,写完成处理器处理写操作的结果;
    3.异步IO操作:由操作系统负责执行,比如Windows的IOCP、Linux的AIO(异步IO)。
  2. Proactor架构的流程
    1.发起异步IO操作:Proactor向操作系统发起异步IO操作(比如异步读、异步写);
    2.操作系统执行IO操作:操作系统负责执行IO操作,不需要服务器线程参与;
    3.IO完成通知:操作系统完成IO操作后,通知Proactor;
    4.处理IO完成结果:Proactor调用Completion Handler处理IO完成的结果。
  3. C#实战:用Proactor架构实现服务器
    在C#中,SocketAsyncEventArgs就是基于Proactor架构实现的——你发起异步IO操作(比如ReceiveAsync、SendAsync),操作系统负责执行,IO完成后触发回调,你处理结果。
    示例:Proactor架构的Socket服务器(和Reactor架构的代码类似,因为C#的SocketAsyncEventArgs同时支持Reactor和Proactor)
    csharp
	// Proactor架构的核心是发起异步IO操作,等待IO完成,处理结果
	// 这里的代码和Reactor架构的代码类似,因为C#的SocketAsyncEventArgs是异步IO的封装
	public class ProactorServer
	{
	private readonly Socket _listenerSocket;
	
	public ProactorServer(int port)
	{
	_listenerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
	_listenerSocket.Bind(new IPEndPoint(IPAddress.Any, port));
	_listenerSocket.Listen(100);
	
	StartAccept();
	Console.WriteLine("Proactor服务器已启动,端口" + port);
	}
	
	// 发起异步连接操作
	private void StartAccept()
	{
	var acceptArgs = new SocketAsyncEventArgs();
	acceptArgs.Completed += AcceptCompleted;
	_listenerSocket.AcceptAsync(acceptArgs);
	}
	
	// 连接操作完成回调:处理连接结果
	private void AcceptCompleted(object sender, SocketAsyncEventArgs e)
	{
	Socket clientSocket = e.AcceptSocket;
	Console.WriteLine($"客户端已连接:{clientSocket.RemoteEndPoint}");
	
	// 发起异步读操作
	StartRead(clientSocket);
	
	// 继续发起下一个连接操作
	StartAccept();
	}
	
	// 发起异步读操作
	private void StartRead(Socket clientSocket)
	{
	var readArgs = new SocketAsyncEventArgs();
	readArgs.SetBuffer(new byte[1024], 0, 1024);
	readArgs.UserToken = clientSocket;
	readArgs.Completed += ReadCompleted;
	clientSocket.ReceiveAsync(readArgs);
	}
	
	// 读操作完成回调:处理读结果
	private void ReadCompleted(object sender, SocketAsyncEventArgs e)
	{
	Socket clientSocket = (Socket)e.UserToken;
	
	if (e.BytesTransferred == 0)
	{
	Console.WriteLine($"客户端已断开:{clientSocket.RemoteEndPoint}");
	clientSocket.Close();
	return;
	}
	
	string message = System.Text.Encoding.UTF8.GetString(e.Buffer, e.Offset, e.BytesTransferred);
	Console.WriteLine($"收到客户端消息:{message}");
	
	// 发起异步写操作
	StartWrite(clientSocket, $"服务器收到:{message}");
	
	// 继续发起下一个读操作
	StartRead(clientSocket);
	}
	
	// 发起异步写操作
	private void StartWrite(Socket clientSocket, string message)
	{
	byte[] buffer = System.Text.Encoding.UTF8.GetBytes(message);
	var writeArgs = new SocketAsyncEventArgs();
	writeArgs.SetBuffer(buffer, 0, buffer.Length);
	writeArgs.Completed += WriteCompleted;
	clientSocket.SendAsync(writeArgs);
	}
	
	// 写操作完成回调:处理写结果
	private void WriteCompleted(object sender, SocketAsyncEventArgs e)
	{
	if (e.SocketError != SocketError.Success)
	{
	Console.WriteLine($"发送消息失败:{e.SocketError}");
	}
	}
	}

关键:Proactor架构的核心是“发起异步IO操作,等待IO完成,处理结果”——你不需要监听事件,只需要发起异步IO操作,然后等待回调,处理结果。
五、Reactor vs Proactor:哪个更好?

架构 优点 缺点 适用场景
Reactor 代码简单,跨平台性好,CPU使用率低 需要手动监听事件,处理事件的时机由开发者控制 大部分高性能服务器场景
Proactor 不需要手动监听事件,操作系统负责IO操作 代码复杂,跨平台性差(Linux的AIO性能一般) Windows平台高性能服务器

结论:在C#中,SocketAsyncEventArgs同时支持Reactor和Proactor——在Windows平台上,SocketAsyncEventArgs基于IOCP(Proactor);在Linux平台上,SocketAsyncEventArgs基于EPOLL(Reactor)。所以你不需要纠结用哪个架构,只要用SocketAsyncEventArgs,就能享受到对应的高性能。
六、高性能服务器架构的最佳实践
1.用异步IO操作:所有IO操作都要用异步版本,比如SocketAsyncEventArgs、HttpClient.GetAsync等;
2.分离IO线程和业务线程:IO线程只负责IO操作,业务线程负责处理业务逻辑,避免IO线程被阻塞;
3.用池化技术:复用SocketAsyncEventArgs、缓冲区、连接等,减少GC压力;
4.处理异常和断开连接:及时关闭Socket,释放资源;
5.监控和调优:监控服务器的CPU、内存、网络使用率,根据监控结果调优参数(比如线程池大小、缓冲区大小)。
七、基础知识拓展

  1. 为什么Reactor/Proactor能支撑高并发?
    异步IO操作:一个线程能处理成千上万个连接的IO操作,不需要为每个连接创建一个线程;
    事件驱动:只在事件发生时才处理,不需要轮询,CPU使用率低;
    模块化:代码分层,每个模块只做一件事,易维护,易扩展。
  2. 如何把Reactor扩展成多Reactor多线程模式?
    创建多个Reactor线程:每个Reactor线程负责监听一部分连接的事件;
    用负载均衡算法:比如轮询、哈希,把连接分配到不同的Reactor线程;
    共享连接池:所有Reactor线程共享一个连接池,方便管理连接。
    示例:多Reactor多线程模式的伪代码
    csharp
	public class MultiReactorServer
	{
	private readonly List<Reactor> _reactors = new List<Reactor>();
	private int _currentReactorIndex = 0;
	
	public MultiReactorServer(int port, int reactorCount)
	{
	for (int i = 0; i < reactorCount; i++)
	{
	var reactor = new Reactor(port + i);
	_reactors.Add(reactor);
	}
	Console.WriteLine("多Reactor服务器已启动,端口" + port + "-" + (port + reactorCount - 1));
	}
	
	// 把连接分配到不同的Reactor线程
	public void AssignConnection(Socket clientSocket)
	{
	var reactor = _reactors[_currentReactorIndex];
	reactor.AddConnection(clientSocket);
	_currentReactorIndex = (_currentReactorIndex + 1) % _reactors.Count;
	}
	}
C# 复制 全屏
  1. 高性能服务器的监控工具 Windows:Performance Monitor(性能监视器)、Process Explorer; Linux:top、htop、netstat、ss; 跨平台:Prometheus + Grafana、ELK(Elasticsearch + Logstash + Kibana)。 八、总结:架构是高性能和可维护性的核心 Reactor架构:事件驱动,代码简单,跨平台性好,适合大部分场景; Proactor架构:异步IO,操作系统负责IO操作,适合Windows平台; C#实战:用SocketAsyncEventArgs实现Reactor/Proactor架构,能支撑10万并发; 最佳实践:分离IO线程和业务线程,用池化技术,处理异常和断开连接,监控和调优。

 本站原创,转载请注明出处:https://www.xin3721.com/ArticlecSharp/c49528.html


相关教程