
简介这份SocketTool是基于C#编写的TCP/UDP网络测试工具面向网络编程开发者和学习者用于快速验证socket通信逻辑、排查连接与收发数据问题。工具内置服务端与客户端模式支持TCP监听连接、UDP广播/多播等常见场景并附有完整源码是理解传输层协议的实用参考。压缩包共610个文件包含71个C#源代码、可执行程序及动态库另有大量图标、截图和界面资源整体仅3.71MB结构紧凑。已有251人学习下载。通过研读源码可深入掌握TCP面向连接、三次握手、可靠传输与滑动窗口机制UDP无连接、低延迟但可能丢包的特性以及C#中Socket类绑定地址、监听、收发数据、异常处理等核心API的实际运用。资源还提供界面设计文件和分类目录便于对照代码查看运行效果适合正在学习网络编程或需要搭建自测环境的中级开发者。1. SocketTool 开箱速览为什么我的 TCP/IP 联调总离不开这个 C# 小工具做过上位机联调的工程师基本都懂这套痛苦设备端说“TCP 连上了但数据收不到”生产端说“发了八次都是粘包”两边拿不出同一份原始字节流光靠口头描述根本没法定位。SocketTool 这种工具解决的就是这个黑匣子问题它把 C# 底层的 Socket 操作封成一个图形界面让你在一个窗口里同时看到 TCP 服务的监听状态、客户端连接状态、Hex 逐字节数据流和定时发送结果。对刚入门的开发人员它能让你十分钟内理解 TCP/IP 的握手与收发流程对干了多年的老手它是联调环节里最顺手的对照基准——别再裸写 Socket 样板代码去调试另一个 Socket 程序那是自己给自己埋雷。2. 工具核心能力与选型逻辑它到底帮你解决了哪几类 TCP/IP 问题2.1 TCP Client / Server 双模式它把 Socket 的状态机封装成了开关C# 原生的 Socket 编程其实不复杂但也不简单。你至少要处理Socket()构造、Bind()、Accept()回调、ReceiveBufferSize与SendBufferSize的分配、断开重连的异常分支。这些样板代码一旦写进调试脚本里真正要验证的协议逻辑反而被淹没。我自己最早调试某模拟项目 X 的通信链路时就吃过这个亏写了个临时 Console 程序做 TCP 服务端结果每次改协议字段都要重新编译一个上午全耗在编译和重启上。SocketTool 这样的调试工具把底层逻辑压缩成了界面上的一个模式开关。Client 模式用于主动连接远程服务Server 模式用于本机监听端口等待连接切换后界面上的连接参数区也会跟着变化。实际联调中两者各有用途Client 模式你的模块是发起方去连设备的 TCP Server或者去连云端的接入网关。这种模式下要关注的是远程 IP 和远程端口连接超时时间的长短直接决定失败时的反馈速度。Server 模式你的程序作为被连接方等待设备或对端模块主动接入。这时候真正决定是否能被外部连上的是本机监听 IP 和端口监听 IP 一旦选错外部连接会一直处于超时状态。工具内部做的事说白了就是下面这段 C# 样板代码的图形化封装// 核心监听逻辑把 Socket 的异步回调封装成可观测状态 TcpListener listener new TcpListener(IPAddress.Any, int.Parse(portBox.Text)); listener.Start(); // 这里必须用异步接受连接否则 UI 线程会卡死 TcpClient client await listener.AcceptTcpClientAsync(); // 获取到客户端后立刻取数据流并设置读取缓冲区 NetworkStream stream client.GetStream(); byte[] buffer new byte[1024]; int bytesRead await stream.ReadAsync(buffer, 0, buffer.Length); // 收到的字节同时透传到 Hex 显示区和状态栏 uiDispatcher.Invoke(() { hexPanel.AppendText(BitConverter.ToString(buffer, 0, bytesRead)); statusLabel.Text string.Format(已连接{0}, client.Client.RemoteEndPoint); });这段逻辑里值得留意的参数是缓冲区大小1024它在工具界面上对应“接收缓冲”配置项。缓冲区设得过小比如 64高频数据流下会出现明明对方发了 800 字节、你这边只拦到 64 的现象设得过大比如 64K粘包时你要从一大段数据里手工切边界反而增加观察成本。我一般习惯先用 1024 起步等业务稳定后再把缓冲调大到 4096 或 8192这个顺序能让粘包问题的暴露过程更清晰。2.2 UDP 单播与组播为什么说无连接反而最容易出幺蛾子TCP 有三次握手、有确认和重传数据丢了还能看出来UDP 就不一样包发出去就完了你永远不确定对端到底收没收到。不少刚转行的人第一次用 UDP 调试时都经历过这种玄学问题收发两个窗口看着都在跑数据就是不对。其实绝大多数时候问题不在工具而在你对 UDP 模式的预期。SocketTool 在 UDP 模式下的设计逻辑是把“本地端口”和“目标地址”拆成两组独立配置。本地端口决定本机绑定哪个口接收数据目标地址决定数据发往何处。组播场景下还需要额外提供组播组的加入操作比如视频流或设备发现协议的调试几乎都要跑在组播环境里。下面这段代码展示了组播模式下 C# 端必须处理的关键设置// 组播接收必须执行的三个步骤缺一步都收不到组播包 UdpClient udpClient new UdpClient(); udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); // 1. 绑定本机端口端口号须与发送端保持一致 udpClient.Client.Bind(new IPEndPoint(IPAddress.Any, 6000)); // 2. 加入组播组这里的地址必须落在 224.0.0.0 - 239.255.255.255 范围 udpClient.JoinMulticastGroup(IPAddress.Parse(239.0.0.88), 20); // 3. 接收时要把缓冲区加大组播场景的帧往往比单播大 byte[] data udpClient.Receive(ref remoteEndpoint);参数上特别容易忽略的是JoinMulticastGroup的第二个参数——TTL。默认值是 1表示组播包只在本机回环口打转跨网段就发不出去。工具界面里如果提供 TTL 或跳数的输入框默认填 20 到 32 比较稳妥既能保证在同一局域网里可靠传输又不会因为跳数太小让包在某个路由器上就被丢弃。选型上我建议把 UDP 模式当成“探针”用而不是当成“压测工具”用。因为 UDP 没有流量控制定时发送间隔一旦低于 50 毫秒组播风暴可能直接把交换机打满最好在持续发送前先用小包验证链路通断。2.3 数据展示逻辑Hex、ASCII 与编码的取舍联调时最容易让人抓狂的是对方发来一段字节你看不懂它是字符串还是二进制指令。SocketTool 这类工具的数据区一般会同时提供 Hex 和 ASCII 两种视图Hex 视图按字节切分每个字节两位十六进制显示ASCII 视图则把每个字节映射成可打印字符。这两个视图相互对照才可能定位是协议字段问题还是编码转换问题。实际使用时的选型建议很直白二进制指令类协议比如 Modbus RTU、自定义帧只看 Hex 视图文本类协议比如 ASCII 行协议、JSON over TCP以 ASCII 视图为主但要随时警惕编码错位。常见翻车场景是对方用 UTF-8 发“温度”你这边默认按 GBK 解码显示出来就是两个问号这不是工具坏了是编码集没对齐。工具界面里一般有个字符编码下拉框联调前先确认双方约定是 UTF-8 无 BOM 还是 GB2312省得对着乱码查半天。Hex 视图还有个额外优势——你可以直接按字节数判断粘包是否发生比如 16 进制行尾出现了不对称的0A 0D大概率是两条消息被塞进了同一个读取缓冲区。3. 可复现的联调流程从配置参数到跑通第一个真实链路3.1 一个典型场景先在本机把 Server 端跑起来拿到 SocketTool 这类工具后不用急着连真实设备。我最习惯的第一步是先在本机回环地址上验证工具自身的收发能力这一步能排除网络因素只验证工具配置是否正确。具体操作序列是这样的打开工具将工作模式切到 TCP Server接收缓冲设为 1024编码选 UTF-8。监听 IP 选择127.0.0.1端口填一个高位端口比如10086。为什么不选 80、8080 这类常见口因为极易与本地已运行的服务冲突测试期间没必要给自己添堵。点击启动监听状态栏会从“停止”变为“监听中”同时给出监听成功的回环地址。同机的另一个 SocketTool 实例或任何 TCP Client 工具连接127.0.0.1:10086连接成功后Server 端界面会弹出新的连接条目附带客户端的来源端口。在 Client 端发送一串带空格的字符串观察 Server 端 Hex 区是否同步出现对应的 ASCII 码。这里对应到工具内部处理逻辑就是典型的AcceptTcpClientAsync回调加线程池处理private async void StartListening() { listener new TcpListener(localAddr, localPort); listener.Start(); while (true) { TcpClient tcpClient await listener.AcceptTcpClientAsync(); // 每接到一个连接就开独立任务读流避免串包 _ Task.Run(() HandleClient(tcpClient)); } } private void HandleClient(TcpClient tcpClient) { byte[] buffer new byte[recvBufferSize]; NetworkStream stream tcpClient.GetStream(); int length 0; while ((length stream.Read(buffer, 0, buffer.Length)) 0) { // 把字节流转成可读信息供界面显示与日志落盘 string hexDump ByteArrayToHex(buffer, length); RaiseDataReceived(hexDump); } }这段处理的巧妙处在于用Task.Run给每个连接开了独立任务保证多个客户端同时接入时不会因为共享同一个NetworkStream而丢数据。如果你用工具时发现多个设备同时接入就出现界面卡顿或数据串包看看是不是工具里每个连接都分配了独立接收线程没有的话果断换更完善一点的工具版本。3.2 连接参数里容易被忽略的三个选项心跳、超时、掉线重连TCP 联调的坑有很大一部分不在协议本身而在连接质量。SocketTool 界面上会出现一堆看似高级的选项实际使用中人手最容易忽略三个心跳包、超时判定和自动重连。心跳包的作用是在没有业务数据的时候维持连接活性。很多抓包分析问题都源于路由器空闲连接老化——两边连着但不说话中间设备就把连接当成僵尸连接回收了。工具里的心跳一般是“每隔 N 秒发送一次固定字节”你只要在输入框里填入 N 值并勾选启用即可。参数选择上有一个经验值心跳间隔要小于对端设备的连接超时时间的一半。比如设备端设的读超时是 60 秒你这边心跳间隔最好在 20 秒到 30 秒之间留足网络抖动余量。超时判定的设置同样关键。做 Client 模式连接时默认的超时时间往往偏长比如 15 秒这在联调阶段会拖慢反馈速度。建议把连接超时压到 3 秒让失败尽快暴露正式批量测试时再放宽到 10 秒以上避免弱网环境下误报失败。工具里如果提供了独立的接收超时字段那是用来判断“连接活着但数据不来了”的一般设成心跳间隔的 2.5 倍左右。下面这段是工具自动重连逻辑的典型实现让我在调试设备反复断电时省掉无数手动点击private async Task MaintainConnectionAsync() { while (!_cancelled) { if (!tcpClient.Connected) { // 重连前强制清理旧 Socket否则句柄泄漏会导致端口被占 tcpClient?.Dispose(); // 连接超时压短让失败更早暴露 using var timeoutCts new CancellationTokenSource(TimeSpan.FromSeconds(3)); try { await tcpClient.ConnectAsync(remoteIp, remotePort, timeoutCts.Token); RaiseStatusNotification(Connected); } catch (OperationCanceledException) { RaiseStatusNotification(ConnectTimeout); } } // 探测周期短于服务端断开阈值保持连接活性 await Task.Delay(TimeSpan.FromSeconds(heartbeatSeconds)); } }留意我对.Dispose()的处理这是血泪经验换来的如果不先 dispose连接断开后旧 Socket 的端口并不会立刻释放状态卡在TIME_WAIT阶段下一次重连大概率会报“端口已被占用”看起来像服务端没起来其实是自己没清理干净。3.3 定时发送与发送区模式让压测用例变得可重复联调设备时经常遇到一种情况需要每 500 毫秒给设备推一条指令或者每隔几秒循环发一组递增序列号看看设备端在不同字节序下的响应是否正常。逐个手动点击发送按钮既不现实也无法保证时间精度。SocketTool 的定时发送功能就是为这个场景准备的。定时发送最常用的配置组合是发送间隔设为 1000 毫秒发送模式设为“循环发送”附带可选的在消息尾部自动追加回车换行。这里必须提醒一个细节发送频率越高越容易触发接收端的粘包拆包问题你在本机看来是两次独立发送但在 TCP 协议层它们可能被合并成一个段传输。所以做高频率定时发送时反而要把接收缓冲调小一些比如降到 256 字节这样每次ReadAsync返回的数据块更接近协议层的分片便于观察粘包规律。对于需要模拟业务递增序号的场景工具一般会提供“自动追加计数”选项它把你的原始报文前缀固定住在尾部加入从 1 开始递增的 4 字节整数每次发送后自动加一。这个设计能很好地模拟真实设备的状态上报包。我之前在调试某跨平台系统的帧同步逻辑时就是靠这一招发现协议里只处理了序列号偶数的帧——这种漏洞平时手动发根本触发不了。4. 避坑排查Socket 联调里最容易翻车的四类问题4.1 端口被占用导致监听启动失败现象点击“启动监听”后工具瞬间报错错误信息类似“无法绑定端口 Address already in use”但换一个端口立刻又正常。新手常以为工具坏了其实八成是端口被别的进程占着。原因Windows 下最常见的是之前跑过的调试程序残留进程占用了端口Socket 关闭后要等TIME_WAIT超时才能重新绑定另外杀毒软件或系统服务也可能悄无声息地占用了高位端口。解决先用命令行确认占用情况再决定释放还是换端口的命令序列如下# 查看 10086 端口被哪个进程占用 netstat -ano | findstr 10086 # 输出结果最后一列是 PID接着查这个 PID 对应的进程名 tasklist | findstr 1234 # 确认是自己的残留调试进程后直接结束 taskkill /PID 1234 /F如果查完发现是系统服务或杀毒软件占用的端口我的建议是不要强行 kill直接换一个 1024 以上的非常用端口。调试场景端口号没有固定必要没必要为了这点事和系统服务死磕。4.2 粘包与拆包的误判问题在业务层而不在 Socket 层现象接收区里面一条记录里出现两条完整消息或者一条消息被切成了两半显示在相邻两条记录里用 Hex 视图看数据行末的字节与下一行开头的字节能拼成一个完整的协议字段。原因TCP 是流式协议Socket 工具负责的只是把字节流不间断地搬给你看它没有也做不到帮你区分消息边界。很多人在项目里看到粘包第一反应是骂工具显示有问题这其实把问题归因错了位置。解决这时候工具的作用是把原始字节完整暴露出来让你判断粘包是否真的发生。如果确认粘包问题基本出在你自己写的协议层——没有定界符、没有长度字段或者接收循环里没做缓冲拼接。先看工具显示的原始数据确认是否真的出现了“两条消息连在一起”不要在定位阶段就去改工具参数那是病急乱投医。4.3 局域网内连不上防火墙、监听 IP 和网段三选一背锅现象工具在 Server 模式正常监听本机用127.0.0.1连接秒通换同一局域网的另一台机器连却一直超时或者直接被拒绝。原因九成情况是三种原因中的一个。第一Windows 防火墙默认阻止了程序对公网的入站连接只放行回环地址第二服务端监听 IP 选的是127.0.0.1而不是0.0.0.0这就限制了只能本机访问第三两边 IP 没在同一网段或路由异常导致客户端发的包根本到不了服务端网卡。解决按顺序排查先用命令在服务端本机验证监听地址再翻防火墙规则# 确认服务端真正监听的地址和端口 netstat -an | findstr 10086 # 如果看到的监听地址是 127.0.0.1:10086说明监听 IP 配错了 # 返回 0.0.0.0:10086 才是监听了所有网卡 # 接着在服务端检查防火墙规则是否放行了 TCP 10086 netsh advfirewall firewall show rule nameall | findstr 10086如果监听地址没问题就在客户端那侧先ping服务端 IP能通再排查端口不通的去看网段和网关设置。防火墙这一项用工具联调时最省事的做法是第一次弹窗直接允许访问专用网络不要选公共网络否则规则不生效又要折腾半天。4.4 中文乱码同一个字节两种编码两种人生现象接上设备后接收区显示的中文全是菱形问号或者偶尔一半正常一半乱码切到 Hex 视图看到的是完全正常的字节排列。原因这是典型的编码不匹配。设备端代码用 UTF-8 发送的字符串工具默认按 GBK 解码又或者工具按 UTF-8 解码但设备端拼接的是 ANSI 字符串。还有一种隐蔽情况是设备端在消息头里声明长度时没算中文三个字节UTF-8 中文占 3 字节导致解析错位。解决第一优先级是确认协议文档里约定的字符串编码然后在工具的编码下拉框里切到对应项第二优先级是用 Hex 视图对字节中文温的 UTF-8 编码是E6 B8 A9如果接收区里看到三字节组里夹着C4 E3GBK 编码就明白是两边编解码不匹配。工具的设计告诉你一个扎心的事实编码问题不是工具能解决的它只是诚实地把字节展示给你剩下的对齐工作还得靠协议双方拿命去对齐。我在联调前的主机习惯是问一句“你们字符串用 UTF-8 还是 GBK”这句话能帮我省掉一整天的乱码排障时间。5. 验证与进阶用法把工具当成可重复的半自动测试台5.1 用构造的异常流量验证对端边界行为工具用熟了之后不要只停留在“看数据”层面它可以当轻量级的模糊测试器用。我一般在联调收尾阶段会在 Hex 发送区手工构造几类特殊报文验证对端程序的边界处理能力一种是无长度字段的畸形帧比如只发AA 55两个字节就干等对端回应看它会不会超时死锁一种是超大帧用定时循环发 32KB 以上的数据块观察对端是否出现缓冲区溢出的日志还有一种是随机字节流直接把十六进制区拉满 4096 字节乱数连续发 20 次看对端程序的崩溃概率。这三种报文不用写任何外部脚本工具本身就能完成。5.2 把日志落盘解析做成回归基线SocketTool 这类工具普遍支持日志自动保存接收区的原始数据会按时间戳写入文件。别小看这个功能它能把一次联调会话变成可对照的回归基线。我通常的做法是每次联调结束把日志文件按日期_测试项_结论的命名规则归档约定三种缀OK、FAIL、MISMATCH。下一次版本迭代后再用同一组测试序列跑一遍用 diff 对比前后两轮 OK 基线文件的字节数差异一版一版累积起来就是完整的回归测试报告。递归对比日志文件的命令序列很简单# 遍历某次测试生成的日志目录对比前后两轮的差异 diff -r ./baseline_2024_round1 ./baseline_2024_round2 # 只看字节数差异过滤掉时间戳不同导致的误报 diff -r --ignore-matching-lines^\[20 ./baseline_1 ./baseline_2这里有个技巧日志里带时间戳的行每轮都会变对比时直接按特征过滤掉剩下的差异才是协议内容的真实变化。做完这步联调数据就从“看一眼就丢”的黑匣子变成项目组可以反复借用的测试资产。5.3 联调前必做的链路自检我从那次某设备项目中收货最大的一句话是给自己定下一个铁律每次正式联调前先花两分钟用工具跑一遍链路自检。TCP 模式就发一组 128 字节的递增序列看接收方逐字节比对是否正确UDP 模式就发 20 个标志包确认通断率达到百分百再往上叠业务数据。这一步能把这套调试链路里属于工具、网线和系统层面的变量全部清零之后出现的任何问题都会直接指向对端协议逻辑或者自己的业务代码。自检过不了绝不开始正式报文。从这个习惯之后我真正体会到了工欲善其事必先利其器的道理希望这个曾被时间验证过的习惯也能帮到你上手 SocketTool少走一次联调弯路。本文还有配套的精品资源点击获取