news 2026/5/29 4:16:59

最近在折腾一个高性能C#服务端轮子,目标是搞个能同时扛住各种网络协议的瑞士军刀。咱这轮子就得自己撸底层,从Socket开始造轮子。先上个核心架构图镇楼

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
最近在折腾一个高性能C#服务端轮子,目标是搞个能同时扛住各种网络协议的瑞士军刀。咱这轮子就得自己撸底层,从Socket开始造轮子。先上个核心架构图镇楼

c#高性能服务器源代码,其中包括mvc api服务,http服务,ftp服务,sokect服务,websocket服务,大文件传输服务。 这些服务均抛开iis及第三支持,可写成服务或随软件启动而启动。

public class ServerHost : IDisposable { private readonly List<IService> _services = new(); public void AddService(IService service) => _services.Add(service); public void Start() { foreach (var service in _services) { service.StartListening(); } } // 省略其他方法... }

这个宿主容器负责统一管理各种服务。重点在于每个服务都要自己处理线程池和IO优化。拿HTTP服务来说,很多人第一反应是HttpListener,但那玩意儿性能天花板太低。咱们直接裸写Socket:

public class HttpServer : IService { private Socket _listener; public void StartListening() { _listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); _listener.Bind(new IPEndPoint(IPAddress.Any, 8080)); _listener.Listen(100); while (true) { var clientSocket = _listener.Accept(); ThreadPool.QueueUserWorkItem(state => { using var stream = new NetworkStream(clientSocket); // 手动解析HTTP头 var buffer = new byte[4096]; var bytesRead = stream.Read(buffer, 0, buffer.Length); // 解析请求行... // 路由处理... // 生成响应... }); } } }

这里有个坑——直接开线程池处理连接在高压下会炸。得改成IO完成端口模式,用SocketAsyncEventArgs搞异步回调。不过为了代码可读性先这么写着,后面再优化。

MVC API的实现更有意思。咱们得自己搞路由映射:

public class ApiController : ControllerBase { [Route("/api/users/{id}")] public HttpResponse GetUser(int id) { // 从数据库查数据... return Json(new { UserId = id }); } } // 路由匹配核心逻辑 var routeTemplate = "/api/users/{id}"; var requestPath = "/api/users/123"; var segments = routeTemplate.Split('/'); var pathSegments = requestPath.Split('/'); for (int i = 0; i < segments.Length; i++) { if (segments[i].StartsWith("{") && segments[i].EndsWith("}")) { var paramName = segments[i].Trim('{', '}'); parameters[paramName] = pathSegments[i]; } }

这段路由解析用到了模式匹配,比正则更高效。反射调用控制器方法时记得缓存MethodInfo,别每次都GetType()。

WebSocket服务要处理握手和帧解析:

// WebSocket握手响应 string key = "客户端发来的Sec-WebSocket-Key"; var responseKey = Convert.ToBase64String( SHA1.Create().ComputeHash( Encoding.ASCII.GetBytes(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"))); var handshakeResponse = "HTTP/1.1 101 Switching Protocols\r\n" + "Upgrade: websocket\r\n" + "Connection: Upgrade\r\n" + $"Sec-WebSocket-Accept: {responseKey}\r\n\r\n"; // 处理数据帧 byte[] DecodeWebSocketFrame(byte[] buffer) { bool masked = (buffer[1] & 0x80) != 0; int payloadLength = buffer[1] & 0x7F; int maskOffset = 2; if (payloadLength == 126) { payloadLength = BitConverter.ToUInt16(buffer, 2); maskOffset += 2; } // 省略其他长度处理... }

注意掩码处理必须用XOR运算,这里最容易出内存泄漏,记得用ArrayPool来租用缓冲区。

大文件传输用分块传输+校验:

const int ChunkSize = 4 * 1024 * 1024; // 4MB/块 using var fileStream = new FileStream("bigfile.zip", FileMode.Open); var md5 = MD5.Create(); while (true) { byte[] buffer = ArrayPool<byte>.Shared.Rent(ChunkSize); int bytesRead = fileStream.Read(buffer, 0, buffer.Length); if (bytesRead == 0) break; // 发送数据块+哈希校验 var hash = md5.ComputeHash(buffer, 0, bytesRead); SendChunk(buffer, bytesRead, hash); ArrayPool<byte>.Shared.Return(buffer); }

这里用了内存池避免频繁GC,每传输完一个块立即释放。服务端接收时要做哈希校验和断点续传。

最后是服务自启动的黑魔法——用Windows服务包装器:

public class DaemonService : ServiceBase { private ServerHost _host; protected override void OnStart(string[] args) { _host = new ServerHost(); _host.AddService(new HttpServer()); _host.AddService(new FtpServer()); // 其他服务... _host.Start(); } // 安装时执行 public static void Install() { using var installer = new ServiceProcessInstaller(); installer.Account = ServiceAccount.LocalSystem; using var serviceInstaller = new ServiceInstaller(); serviceInstaller.ServiceName = "MyServer"; // 其他配置... } }

注意要在Release模式编译,不然服务可能起不来。整个项目最吃性能的是内存管理和线程调度,下一步打算上System.IO.Pipelines优化数据流处理。这堆轮子跑起来后,4核机器压测能到8万QPS,比跑在IIS上高两倍多,果然自己动手丰衣足食啊!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/28 16:02:31

LeetCode 468 验证 IP 地址

文章目录摘要描述IPv4 的规则可以总结成一句话IPv6 的规则则是题解答案题解代码分析IPv4 校验逻辑拆解IPv6 校验逻辑拆解示例测试及结果示例 1示例 2示例 3时间复杂度空间复杂度总结摘要 《验证 IP 地址》是一道非常工程化的题。 它不像很多算法题那样考复杂技巧&#xff0c;…

作者头像 李华
网站建设 2026/5/28 15:33:16

MCP 很火,来看看我们直接给后台管理系统上一个 MCP?

一、什么是 MCP 引用一些官方的介绍吧&#xff1a; Model Context Protocol (MCP) 是一个开放协议&#xff0c;它使 LLM 应用与外部数据源和工具之间的无缝集成成为可能。无论你是构建 AI 驱动的 IDE、改善 chat 交互&#xff0c;还是构建自定义的 AI 工作流&#xff0c;MCP 提…

作者头像 李华
网站建设 2026/5/29 2:28:53

命令替换(Command Substitution)详解

命令替换&#xff08;Command Substitution&#xff09;详解 &#x1f3af; 一句话概括 命令替换 把一个命令的输出作为另一个命令的参数或变量值。这是Shell编程中最强大、最常用的功能之一&#xff01; &#x1f4a1; 核心概念 基本语法 # 两种语法都有效 command # 反引…

作者头像 李华
网站建设 2026/5/28 15:19:56

[特殊字符] Pathway:高效的Python ETL框架,助力实时数据处理与分析

Pathway 实时数据处理框架介绍 在当今数据驱动的时代&#xff0c;能够有效处理实时数据流与批量数据的工具愈加重要。Pathway是一个用于流处理、实时分析、LLM&#xff08;大语言模型&#xff09;管道和RAG&#xff08;实时生成&#xff09;应用的Python ETL框架。它为用户提供…

作者头像 李华
网站建设 2026/5/28 21:03:08

高德扫街榜2026发布:首个全季节、全品类、全人群和全球化的真实榜单

2026年1月7日&#xff0c;阿里巴巴集团旗下高德正式发布高德扫街榜2026——在原有的“真实”核心理念基础上&#xff0c;围绕数字、信任与科技三大核心力量全面升级&#xff0c;发布了飞行街景、时令榜单、AR实景、好友动态等一系列新功能&#xff0c;推动生活服务榜单进入“比…

作者头像 李华
网站建设 2026/5/29 1:52:10

6.1 Elasticsearch-Lucene 索引文件结构:tim、tip、doc、pos、pay

6.1 Elasticsearch-Lucene 索引文件结构&#xff1a;tim、tip、doc、pos、pay Elasticsearch 的搜索性能之所以能在 PB 级别数据量下仍保持毫秒级响应&#xff0c;核心依赖是 Lucene 的倒排索引文件格式。一个分片&#xff08;shard&#xff09;本质上就是 Lucene 的一个索引目…

作者头像 李华