跳转到主内容
新派编程网 - 新潮编程理念,全新技术课堂!

C#怎么实现WebSocket通信_C#使用ClientWebSocket连接服务器【实时】

ClientWebSocket连接失败主因是系统版本不兼容(Win7/8不支持)或证书无效;发送需正确使用ArraySegment并避免缓冲区复用;接收须循环拼接直至EndOfMessage为true;需手动实现心跳与状态检查下的重连。 ClientWebSocket 连接失败的常见报错和原因 直接 new
ClientWebSocket()
并调用
ConnectAsync()
却卡住或抛出
WebSocketException
,大概率不是代码写错了,而是没处理好底层依赖或网络策略。 Windows 7/8 默认不支持 WebSocket 协议栈,
ClientWebSocket
在这些系统上会静默降级失败(.NET Core 2.1+ 要求 Windows 8.1 或 Server 2012 R2+);另外,如果目标地址是
wss://
但证书无效,.NET 不会像浏览器那样弹提示,而是直接抛
HttpRequestException
带 “The remote certificate is invalid”。 检查运行环境:用
Environment.OSVersion
确认系统版本,旧系统必须用第三方库(如
WebSocket4Net
) 调试证书问题:临时加
ServicePointManager.ServerCertificateValidationCallback = (a, b, c, d) => true;
(仅测试!) 别漏 await:
ConnectAsync()
是异步方法,忘记 await 会导致连接未完成就执行后续逻辑 发送二进制数据时容易踩的坑
SendAsync()
的第一个参数是
ArraySegment
,不是
byte[]
或
Memory
(.NET 5+ 支持后者,但默认重载仍是前者),传错类型不会编译报错,但可能发空包或触发
ArgumentException
。 更隐蔽的问题是缓冲区复用:如果在发送后立刻重置或重用同一段
byte[]
,而
SendAsync()
还没真正发出(尤其在高并发下),就会导致发出去的是脏数据。 发送前确保
ArraySegment
的
Offset
和
Count
设置正确,不要传整个大数组却只设
Count=1
避免跨调用复用缓冲区;简单做法是每次发新消息都
new byte[...]
,或用
ArrayPool.Shared.Rent()
配合
.Return()
发送字符串建议用
Encoding.UTF8.GetBytes()
转换,别用
Encoding.Default
—— 中文环境可能变成 GB2312,服务端解析失败 如何安全地接收并解析连续消息
ReceiveAsync()
不保证一次收完一整条消息。WebSocket 协议允许分帧(fragmented frame),尤其当消息较大或网络分片时,你可能会收到多个
WebSocketReceiveResult
,其中只有最后一个的
EndOfMessage
是
true
。 C函数速查手册(CHM版) C函数速查手册(CHM版) 下载 直接把每次
ReceiveAsync()
的结果当完整消息处理,会导致 JSON 解析失败、协议头错位等诡异问题。 必须循环调用
ReceiveAsync()
,拼接所有
buffer
,直到
result.EndOfMessage == true
用
result.MessageType
区分
Binary
/
Text
/
Close
,收到
Close
必须主动调用
CloseAsync()
,不能忽略 设置接收超时:在
CancellationTokenSource
中设定合理 timeout(比如 30 秒),防止因网络中断卡死在
ReceiveAsync()
心跳保活和异常断连后的自动重连
ClientWebSocket
不内置心跳机制。服务器通常 30–60 秒无数据就关连接,客户端若只发不收、也不发 ping,就会被静默踢掉。 单纯捕获
WebSocketException
后重连也不够 —— 异常可能发生在 send/receive 过程中,此时 socket 状态已是
Aborted
或
CloseReceived
,再调
ConnectAsync()
会抛
InvalidOperationException
。 用
WebSocket.State
判断当前状态,只对
Open
或
Connecting
才发心跳;状态为
CloseSent
/
Aborted
时必须新建
ClientWebSocket
实例 心跳建议用
SendAsync()
发空
Text
帧(如
"ping"
),比
SendPing()
兼容性更好(某些代理会丢 ping 帧) 重连不要用固定间隔,加 jitter(比如 1~3 秒随机),避免大量客户端同时重连压垮服务器 WebSocket 的“实时”感很依赖连接稳定性,但
ClientWebSocket
本身只是个裸通道,所有保活、重连、粘包处理都得自己补全。最容易被忽略的是:没检查
WebSocket.State
就盲目调用方法,结果在已关闭的实例上操作,抛出的异常信息还特别不直观。

相关文章