C# TCP/IP 服务端与客户端源码实战:从监听、粘包到断线重连
简介这份源码资源面向具备一定 C# 基础、希望深入理解网络通信机制的开发者与计算机专业学生围绕 TCP/IP 协议给出服务端与客户端的完整实现范例。内容基于 .NET 的 System.Net 与 System.Net.Sockets 命名空间涵盖 TcpListener 侦听端口、TcpClient 建立连接、NetworkStream 收发数据等核心流程并延伸至多客户端并发、多线程与 async/await 异步编程、SslStream 加密传输及错误处理等进阶主题可作为网络编程课程实验或项目原型的参考。压缩包共 273 个文件约 5.94MB以 77 个 cs 源码文件为主体辅以 csproj、sln 工程文件、resx 资源、exe 与 dll 编译产物及 txt 说明工程结构完整可直接在 Visual Studio 中打开调试。目前已有 69 人学习适合对照源码梳理通信流程、理解连接管理与资源释放思路。1. 从一份 C# TCP/IP 源码说起服务端与客户端到底该怎么写很多人第一次拿到「C# 写的 TCP/IP 服务端与客户端源码」这类东西是在做上位机、设备网关或者内部工具的时候。需求很朴素一台机器监听端口另一台机器连上来双方收发字节流最好还能同时带几十上百个连接。真动手才发现网上抄来的示例要么只能一对一要么粘包粘到怀疑人生要么客户端一断线服务端就抛异常。这篇笔记就围绕这份源码该有的骨架把服务端和客户端从监听、连接、收发到断线重连整条链路拆开讲清楚顺带把 C# 里TcpListener、TcpClient、NetworkStream这几个类的边界和参数说明白。适合正在写 C# 上位机、做服务端接口测试、或者需要自己搭一套轻量通信层的同学新手能照着跑通熟手能对照检查自己的实现有没有埋雷。2. 服务端骨架TcpListener 监听、AcceptTcpClient 与并发模型怎么选2.1 为什么服务端不能只写一个 Accept 循环最朴素的写法是listener.AcceptTcpClient()拿到一个连接处理完再 Accept 下一个。这种写法在只有一个客户端时没问题一旦第二个客户端连上来它只能排队等着前一个不断开就永远轮不到它。TCP/IP 服务端的本质是「一个监听端口 N 个独立会话」每个会话有自己的收发节奏所以必须把 Accept 和会话处理拆开。C# 里常见的三种并发模型模型写法适用场景代价同步阻塞 每连接一线程new Thread(HandleClient)连接数几十以内逻辑简单线程多上下文切换开销大异步回调BeginAcceptTcpClient老项目兼容回调嵌套难维护async/awaitAcceptTcpClientAsync现代项目首选需要理解异步语义我一般直接上async/await代码线性、异常好捕获连接数几百也没压力。下面是最小可运行的服务端骨架。using System; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; class TcpServer { private readonly TcpListener _listener; private readonly CancellationTokenSource _cts new CancellationTokenSource(); public TcpServer(int port) { // IPAddress.Any 表示监听本机所有网卡端口由外部传入 _listener new TcpListener(IPAddress.Any, port); } public async Task StartAsync() { _listener.Start(); Console.WriteLine($服务端已启动监听端口 {((IPEndPoint)_listener.LocalEndpoint).Port}); while (!_cts.IsCancellationRequested) { // AcceptTcpClientAsync 不会阻塞线程连接到来时才继续 TcpClient client await _listener.AcceptTcpClientAsync(); // 每个连接丢到独立任务里不阻塞 Accept 循环 _ HandleClientAsync(client, _cts.Token); } } private async Task HandleClientAsync(TcpClient client, CancellationToken token) { string remote client.Client.RemoteEndPoint?.ToString() ?? unknown; Console.WriteLine($客户端接入: {remote}); try { using (client) using (NetworkStream stream client.GetStream()) { byte[] buffer new byte[4096]; while (!token.IsCancellationRequested) { // ReadAsync 返回 0 表示对端正常关闭 int read await stream.ReadAsync(buffer, 0, buffer.Length, token); if (read 0) break; string text Encoding.UTF8.GetString(buffer, 0, read); Console.WriteLine($[{remote}] 收到: {text}); // 原样回显实际项目里换成业务处理 byte[] echo Encoding.UTF8.GetBytes($echo:{text}); await stream.WriteAsync(echo, 0, echo.Length, token); } } } catch (Exception ex) { // 客户端强制断开时这里会抛 IOException属正常现象 Console.WriteLine($连接 {remote} 异常结束: {ex.Message}); } finally { Console.WriteLine($客户端断开: {remote}); } } public void Stop() { _cts.Cancel(); _listener.Stop(); } }逻辑说明StartAsync里只做一件事——不断接受新连接把每个连接交给HandleClientAsync。HandleClientAsync用using保证TcpClient和NetworkStream一定释放ReadAsync返回 0 是判断对端关闭的标准做法不要用client.Connected去判断那个属性经常骗人。参数说明buffer大小 4096 是经验值太小会频繁触发读太大浪费内存IPAddress.Any换成IPAddress.Loopback就只允许本机连AcceptTcpClientAsync没有超时参数要控制接入速率得自己在外面加信号量。2.2 端口、 backlog 与 KeepAlive 三个必调参数TcpListener构造之后、Start之前有几个参数值得单独说。第一是端口。0 到 1023 是系统保留端口普通程序别碰1024 到 49151 是注册端口自己用选 8000 以上比较稳。端口被占用时Start()会抛SocketException错误码AddressAlreadyInUse这时候要么换端口要么查是谁占着。第二是 backlog。TcpListener.Start(int backlog)里的 backlog 是「已完成三次握手但还没被 Accept 的队列长度」默认值在不同平台不一样。高并发接入场景下如果 Accept 循环处理慢队列满了新连接会被系统拒绝。我一般显式写Start(512)配合异步 Accept 基本不会丢连接。第三是 KeepAlive。TCP 默认两小时才发一次保活探测对长连接业务来说太久了客户端拔网线服务端可能两小时才知道。可以在连接建立后设置client.Client.SetSocketOption( SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true); // 前两个参数是 Windows 特有的单位毫秒 client.Client.IOControl( IOControlCode.KeepAliveValues, BitConverter.GetBytes(1).Concat(BitConverter.GetBytes(10000)) .Concat(BitConverter.GetBytes(5000)).ToArray(), null);这段设置的意思是10 秒没有数据往来就开始探测探测间隔 5 秒。注意IOControl这套在 Linux 上不生效跨平台项目得用应用层心跳代替这也是后面避坑章节要展开的点。3. 客户端实现TcpClient 连接、收发与断线重连的完整写法3.1 连接超时为什么必须自己控制TcpClient.Connect和ConnectAsync默认的超时跟操作系统有关Windows 上没连上的地址可能要等二十秒才返回。做上位机时这个体验是灾难性的——界面卡死二十秒。所以连接必须自己加超时。using System; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; class TcpClientWrapper { private TcpClient _client; private NetworkStream _stream; private readonly string _host; private readonly int _port; public TcpClientWrapper(string host, int port) { _host host; _port port; } public async Taskbool ConnectAsync(int timeoutMs 3000) { _client new TcpClient(); using (var cts new CancellationTokenSource(timeoutMs)) { try { // ConnectAsync 支持 CancellationToken超时会抛 OperationCanceledException await _client.ConnectAsync(_host, _port).WaitAsync(cts.Token); _stream _client.GetStream(); Console.WriteLine(连接成功); return true; } catch (OperationCanceledException) { Console.WriteLine($连接 {_host}:{_port} 超时({timeoutMs}ms)); _client?.Close(); return false; } catch (SocketException ex) { Console.WriteLine($连接失败: {ex.SocketErrorCode}); _client?.Close(); return false; } } } public async Task SendAsync(string message) { if (_stream null) throw new InvalidOperationException(尚未连接); byte[] data Encoding.UTF8.GetBytes(message); await _stream.WriteAsync(data, 0, data.Length); } public async Taskstring ReceiveAsync() { byte[] buffer new byte[4096]; int read await _stream.ReadAsync(buffer, 0, buffer.Length); if (read 0) return null; // 服务端关闭 return Encoding.UTF8.GetString(buffer, 0, read); } public void Close() { _stream?.Close(); _client?.Close(); } }逻辑说明WaitAsync(cts.Token)是 .NET 6 之后给任意 Task 加超时的通用写法比Task.WhenAny干净。ConnectAsync抛SocketException时看SocketErrorCodeConnectionRefused说明服务端没监听HostUnreachable说明网络不通这两个排查方向完全不同。参数说明timeoutMs默认 3000 是内网场景的经验值跨公网可以放到 5000 到 8000buffer同样 4096和服务端保持一致便于对照。3.2 断线重连别用 while(true) 硬怼客户端断线重连最常见的翻车写法是while(true) { try { Connect(); break; } catch { Thread.Sleep(1000); } }。这种写法在服务端长时间不可用时会把 CPU 和日志刷爆而且没有退避服务端刚恢复就被一堆客户端同时冲击。我一般用指数退避加最大间隔public async Task ReconnectLoopAsync(CancellationToken token) { int delay 1000; // 初始 1 秒 const int maxDelay 30000; // 最大 30 秒 while (!token.IsCancellationRequested) { if (await ConnectAsync()) { delay 1000; // 连上后重置退避 return; } Console.WriteLine(${delay}ms 后重试); await Task.Delay(delay, token); // 每次失败翻倍封顶 maxDelay delay Math.Min(delay * 2, maxDelay); } }逻辑说明连上就重置delay保证下次断线还是从 1 秒开始失败就翻倍避免服务端没起来时疯狂重试。token用来在程序退出时中断重连循环不然关窗口时线程还挂着。参数说明初始 1 秒适合内网公网可以放到 2 到 3 秒maxDelay30 秒是平衡「恢复速度」和「服务端压力」的结果再大用户感知就明显了。4. 粘包与拆包TCP 字节流为什么不能当消息用4.1 粘包的本质是 TCP 没有消息边界很多人第一次写 TCP 通信会踩这个坑客户端连续Send(AAA)、Send(BBB)服务端一次Read收到AAABBB或者反过来一条消息被拆成两次收到。这不是 bug是 TCP 的设计——它只保证字节顺序不保证「一次发对应一次收」。解决思路只有一条在应用层自己定边界。常见三种方案方案格式优点缺点固定长度每条消息 N 字节解析简单消息长度受限浪费带宽分隔符消息 \n可读性好消息里不能出现分隔符长度前缀4 字节长度 消息体通用、高效需要处理半包长度前缀是最通用的下面给一个完整的收发封装。// 发送先写 4 字节大端长度再写消息体 public static async Task SendMessageAsync(NetworkStream stream, byte[] payload) { byte[] lengthPrefix BitConverter.GetBytes(payload.Length); if (BitConverter.IsLittleEndian) Array.Reverse(lengthPrefix); // 统一用大端跨平台一致 await stream.WriteAsync(lengthPrefix, 0, 4); await stream.WriteAsync(payload, 0, payload.Length); } // 接收先读满 4 字节长度再按长度读满消息体 public static async Taskbyte[] ReadMessageAsync(NetworkStream stream) { byte[] lengthBuffer await ReadExactAsync(stream, 4); if (lengthBuffer null) return null; // 对端关闭 if (BitConverter.IsLittleEndian) Array.Reverse(lengthBuffer); int length BitConverter.ToInt32(lengthBuffer, 0); if (length 0 || length 10 * 1024 * 1024) throw new InvalidOperationException($非法消息长度: {length}); return await ReadExactAsync(stream, length); } // 辅助方法保证读满 count 字节处理半包 private static async Taskbyte[] ReadExactAsync(NetworkStream stream, int count) { byte[] buffer new byte[count]; int offset 0; while (offset count) { int read await stream.ReadAsync(buffer, offset, count - offset); if (read 0) return null; // 对端关闭 offset read; } return buffer; }逻辑说明ReadExactAsync是核心ReadAsync一次可能只返回部分数据必须循环读到offset count才算一条完整消息。长度前缀统一用大端避免大小端机器互通时出错。参数说明长度上限设 10MB 是防御性编程防止对端发个int.MaxValue让你直接 OOM实际项目按业务最大消息调整一般 1MB 以内够用。4.2 心跳包KeepAlive 不够用时的应用层方案前面提过 TCP KeepAlive 默认两小时跨平台还不好设。长连接业务里我一般加应用层心跳客户端每 30 秒发一个固定格式的心跳包服务端收到就更新「最后活跃时间」超过 90 秒没收到就主动断开。// 服务端维护每个连接的最后活跃时间 private readonly ConcurrentDictionarystring, DateTime _lastActive new(); // 收到任何数据都刷新 _lastActive[remote] DateTime.UtcNow; // 后台定时扫描清理超时连接 private async Task CleanupLoopAsync(CancellationToken token) { while (!token.IsCancellationRequested) { await Task.Delay(30000, token); var now DateTime.UtcNow; foreach (var kv in _lastActive) { if ((now - kv.Value).TotalSeconds 90) { Console.WriteLine($心跳超时断开 {kv.Key}); // 这里需要能根据 remote 找到对应 TcpClient 并关闭 } } } }逻辑说明心跳间隔 30 秒、超时 90 秒是「容忍两次丢包」的经验值。心跳包本身可以是一个特殊前缀的短消息业务层收到直接忽略。参数说明心跳间隔别小于 10 秒否则连接数一多网络全是心跳超时至少是心跳间隔的 2 到 3 倍给网络抖动留余量。5. 避坑与排查C# TCP/IP 源码里最容易翻车的 5 个点5.1 现象客户端断开后服务端抛 IOException原因客户端强制关闭比如直接杀进程时服务端正在ReadAsync会抛IOException: 远程主机强迫关闭了一个现有的连接。这是 TCP 的正常行为不是代码 bug。解决在HandleClientAsync里把IOException和ObjectDisposedException单独 catch 掉只记日志不往上抛。判断对端关闭的正确方式是ReadAsync返回 0而不是client.Connected。5.2 现象服务端跑一段时间后端口被占用重启失败原因TcpListener.Stop()之后端口会进入TIME_WAIT状态默认持续几十秒到几分钟期间再Start同一个端口会抛AddressAlreadyInUse。解决在Start之前设置ReuseAddress_listener.Server.SetSocketOption( SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); _listener.Start(512);注意这个选项在 Windows 和 Linux 上语义略有差异生产环境更稳妥的做法是让程序优雅退出别频繁重启。5.3 现象中文消息收到乱码原因发送端用Encoding.UTF8接收端用Encoding.Default或者反过来。Encoding.Default在中文 Windows 上是 GBK跨平台必翻车。解决两端统一用Encoding.UTF8并且长度前缀算的是「UTF-8 编码后的字节数」不是字符串的Length。你好.Length是 2但 UTF-8 编码后是 6 字节这个差异是乱码和截断的常见来源。5.4 现象连接数一多服务端内存暴涨原因每个连接分配了 4096 字节 buffer加上TcpClient和NetworkStream对象一万个连接就是几十 MB 起步。如果 buffer 开到 64KB直接几百 MB。解决buffer 按业务最大消息设别图省事开大连接数上千时考虑用SocketAsyncEventArgs做零分配收发或者上System.IO.Pipelines。普通上位机几十个连接现在的写法完全够用别过度设计。5.5 现象客户端连上了但收不到数据原因服务端WriteAsync之后没有Flush或者客户端ReadAsync的 buffer 太小一条消息被拆成多次读但客户端只读了一次。解决NetworkStream默认不缓冲WriteAsync直接发出不需要Flush问题多半在客户端没按长度前缀循环读。用第 4 章的ReadExactAsync替换裸ReadAsync这个坑基本就消失了。6. 进阶技巧用 Wireshark 和日志把通信问题钉死写完能跑只是第一步真正省时间的是出问题时能快速定位。我一般做两件事抓包和结构化日志。抓包用 Wireshark过滤条件直接写tcp.port 8888能看到三次握手、每次收发的字节数、FIN 和 RST。粘包问题在 Wireshark 里一目了然——你能看到两个应用层消息被合在一个 TCP 段里或者一条消息跨了两个段。这一步能省掉大量「到底是发送端还是接收端的问题」的扯皮。日志方面别用Console.WriteLine打天下。给每条收发记录加上连接标识、时间戳、字节数void LogTraffic(string connId, string direction, byte[] data) { // 只打前 64 字节避免大消息刷爆日志 int preview Math.Min(data.Length, 64); string hex BitConverter.ToString(data, 0, preview).Replace(-, ); Console.WriteLine(${DateTime.Now:HH:mm:ss.fff} [{connId}] {direction} {data.Length}B | {hex}); }connId用remote endpoint或者自增编号都行关键是同一条连接的所有日志能串起来。十六进制预览比直接打字符串有用因为二进制协议里很多字段不是可打印字符。还有一个我踩过的坑调试时把TcpClient.NoDelay设成false小消息会被 Nagle 算法攒着一起发看起来像「延迟很高」。对实时性有要求的场景连接建立后立刻设client.NoDelay true代价是每个小包都单独发网络利用率略降但延迟稳定。最后说个习惯每次改完收发逻辑先写一个「回环测试」——服务端和客户端跑在同一台机器上用127.0.0.1连发一万条随机长度的消息校验每条都完整收到。这个测试能在五分钟内暴露粘包、半包、编码、长度前缀的所有问题比在真实网络里瞎试高效得多。我现在的项目里这套回环测试是提交代码前的固定动作希望帮到你。本文还有配套的精品资源点击获取

相关新闻

Spring Boot校园信息服务系统毕设全攻略:从需求到部署

Spring Boot校园信息服务系统毕设全攻略:从需求到部署

每年的毕业设计季,总会有一批人被"校园信息服务平台"这类题目包围。我这两年陆续带过好几个类似方向的项目,从选题开题到答辩收尾,踩过的坑和总结的经验都能写满一个笔记本了。这次就以"基于Spring Boot的校园移动信息服务系统…

2026/10/12 1:19:15 阅读更多 →
React Native集成鸿蒙组件:从ArkTS到分布式能力的完整实践

React Native集成鸿蒙组件:从ArkTS到分布式能力的完整实践

这两年做跨端开发的朋友,十个里有八个都在问同一个问题:React Native 项目到底怎么接鸿蒙组件?这问题表面看着简单,拆开其实有两层:一是鸿蒙开发的基础你得先啃下来,二是 RN 和鸿蒙两套运行时之间的桥怎么搭…

2026/10/12 1:19:17 阅读更多 →
C语言冒泡排序从原理到优化:边界问题与调试实战

C语言冒泡排序从原理到优化:边界问题与调试实战

冒泡排序大概是很多人在C语言里接触的第一个非平凡算法,也是容易被轻视的一个。代码看起来就十几行,逻辑似乎一行就能说清楚,可真到了笔试、面试、或者自己在项目里写排序时,反而容易踩到各种边界问题和优化取舍。做某嵌入式项目的…

2026/10/12 1:19:23 阅读更多 →

最新新闻

T3 Stack全栈实践:tRPC与Prisma打通端到端类型安全

T3 Stack全栈实践:tRPC与Prisma打通端到端类型安全

最近在折腾全栈项目的时候,我把研究重点放在了 t3code 这个代号下的整套技术组合上。如果你也关注过 Next.js 生态,T3 Stack 这个名字多半不陌生,它把 Next.js、TypeScript、tRPC、Prisma、Tailwind CSS、NextAuth 这六样东西打包成一套开箱即…

2026/10/13 10:09:29 阅读更多 →
RAID阵列配置与数据安全(进阶篇):原理、方案与优化

RAID阵列配置与数据安全(进阶篇):原理、方案与优化

本文深入探讨RAID阵列配置与数据安全(进阶篇),涵盖背景分析、原理剖析、实战步骤、配置示例、优化建议和避坑指南。很多团队在服务器与运维场景中都会遇到与RAID阵列配置与数据安全(进阶篇)相关的挑战。本文结合生产环…

2026/10/13 10:09:29 阅读更多 →
AnyPS5 泛化接入实战:PS5 串流跨设备、跨网络与输入映射优化指南

AnyPS5 泛化接入实战:PS5 串流跨设备、跨网络与输入映射优化指南

1. 从“AnyPS5”这个名字说起:它到底想解决什么问题第一次看到“AnyPS5”这个标题,我脑子里蹦出来的第一个念头是:这大概率是一个围绕 PlayStation 5 生态做“泛化接入”或“跨端体验”的项目。为什么这么说?因为“Any”这个前缀在…

2026/10/13 10:09:29 阅读更多 →
基于STM32单片机直流无刷电机PID控制温度PWM调速编码器蓝牙无线APP/WiFi无线APP/摄像头视频监控/云平台设计S457

基于STM32单片机直流无刷电机PID控制温度PWM调速编码器蓝牙无线APP/WiFi无线APP/摄像头视频监控/云平台设计S457

STM32-S457-无刷电机测速编码器温度超速高温报警PID控制PWM10档加减速正反转电源OLED屏声光提醒按键(无线方式选择)产品功能描述:本系统由STM32F103C8T6单片机核心板、OLED屏、(无线蓝牙/无线WIFI/无线视频监控/联网云平台模块-可选)、电压转…

2026/10/13 10:08:26 阅读更多 →
基于STM32单片机激光测距仪TOF激光传感器VL53L1X倒车雷达蓝牙无线APP/WiFi无线APP/摄像头视频监控/云平台设计S450

基于STM32单片机激光测距仪TOF激光传感器VL53L1X倒车雷达蓝牙无线APP/WiFi无线APP/摄像头视频监控/云平台设计S450

STM32-S450-电磁波检测舵机保护报警频率变化预警阈值保护阈值超阈值报警OLED屏声光提醒按键(无线方式选择)产品功能描述:本系统由STM32F103C8T6单片机核心板、OLED屏、(无线蓝牙/无线WIFI/无线视频监控/联网云平台模块-可选)、激光测距传感器…

2026/10/13 10:08:26 阅读更多 →
敏捷开发全流程会议实战指南:从Sprint规划到回顾会的高效落地

敏捷开发全流程会议实战指南:从Sprint规划到回顾会的高效落地

敏捷开发这几年几乎成了软件团队的标配词汇,但真正把“敏捷”落实到日常工作中的,往往都绕不开一件事:开会。从需求进待办列表到版本发布,串起整个迭代的其实是一套固定的会议节奏——Sprint规划、每日站会、Sprint评审、Sprint回…

2026/10/13 10:08:26 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 14:48:49 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →