使用WebSocketSharp获取验证码Token时遇平台不支持及对象已释放异常
我尝试从Habbo的验证码接口获取Token,用WebSocketSharp搭建本地WebSocket服务配合Tampermonkey脚本传输,但出现以下错误:
29/08/2022 22:00:05|Error|QueueUserWorkItemCallbackDefaultContext.Execute|Operation is not supported on this platform.
29/08/2022 22:00:06|Fatal|<>c__DisplayClass48_0.<ReadBytesAsync>b__0|System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'System.Net.Sockets.NetworkStream'.
at System.Net.Sockets.NetworkStream.<ThrowIfDisposed>g__ThrowObjectDisposedException|63_0()
at System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult)
at WebSocketSharp.Ext.<>c__DisplayClass48_0.<ReadBytesAsync>b__0(IAsyncResult ar)
Tampermonkey脚本代码:
// ==UserScript== // @name Captcha Service // @namespace mservice // @version 1.0 // @description no description // @author Moch // @match https://www.habbo.com.br/api/public/captcha* // @grant none // ==/UserScript== (function () { 'use strict'; var socket = new WebSocket("ws://127.0.0.1:8080"); socket.onopen = () => { const urlParams = new URLSearchParams(window.location.search); if (urlParams.has("token") && urlParams.get("token") !== "") { socket.send(urlParams.get("token")); } } })();
C#服务端代码:
using WebSocketSharp; using WebSocketSharp.Server; public class Laputa : WebSocketBehavior { protected override void OnMessage(MessageEventArgs e) { Console.WriteLine(e.Data); } } static void Main(string[] args) { var wssv = new WebSocketServer("ws://127.0.0.1:8080"); wssv.AddWebSocketService<Laputa>("/"); wssv.Start(); Console.ReadKey(true); wssv.Stop(); }
已尝试切换至WebSocketSharp-netstandard和WebSocketSharkFork,错误依旧。
1. 平台兼容性问题
第一个错误Operation is not supported on this platform说明WebSocketSharp在当前运行的.NET平台上存在API兼容问题,比如旧版本对异步IO的处理和.NET Core/.NET 5+的网络栈不兼容。
解决办法:
- 改用.NET原生的
System.Net.WebSockets实现,兼容性更好。示例服务端代码:using System; using System.Net; using System.Net.WebSockets; using System.Text; using System.Threading; using System.Threading.Tasks; class Program { static async Task Main(string[] args) { var listener = new HttpListener(); listener.Prefixes.Add("http://127.0.0.1:8080/"); listener.Start(); Console.WriteLine("WebSocket服务已启动,等待连接..."); while (true) { var context = await listener.GetContextAsync(); if (context.Request.IsWebSocketRequest) { var webSocketContext = await context.AcceptWebSocketAsync(null); _ = HandleWebSocketConnection(webSocketContext.WebSocket); } else { context.Response.StatusCode = 400; context.Response.Close(); } } } private static async Task HandleWebSocketConnection(WebSocket webSocket) { var buffer = new byte[1024 * 4]; WebSocketReceiveResult result; try { do { result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None); var message = Encoding.UTF8.GetString(buffer, 0, result.Count); Console.WriteLine("收到Token: " + message); } while (!result.CloseStatus.HasValue); await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None); } catch (Exception ex) { Console.WriteLine("连接异常: " + ex.Message); if (webSocket.State == WebSocketState.Open) { await webSocket.CloseAsync(WebSocketCloseStatus.InternalServerError, "服务器异常", CancellationToken.None); } } finally { webSocket.Dispose(); } } }
2. 连接过早关闭问题
第二个错误Cannot access a disposed object: System.Net.Sockets.NetworkStream通常是因为WebSocket连接在异步操作完成前就被释放了。原Tampermonkey脚本发送完Token后没有保持连接,浏览器可能主动关闭连接,导致服务端异步读取失败。
解决办法:
- 修改脚本,发送完Token后延迟关闭连接,或者添加错误/关闭事件处理:
// ==UserScript== // @name Captcha Service // @namespace mservice // @version 1.0 // @description no description // @author Moch // @match https://www.habbo.com.br/api/public/captcha* // @grant none // ==/UserScript== (function () { 'use strict'; var socket = new WebSocket("ws://127.0.0.1:8080"); socket.onopen = () => { const urlParams = new URLSearchParams(window.location.search); if (urlParams.has("token") && urlParams.get("token") !== "") { socket.send(urlParams.get("token")); // 延迟1秒关闭,确保服务端接收完成 setTimeout(() => socket.close(), 1000); } }; socket.onerror = (error) => { console.error("WebSocket错误:", error); }; socket.onclose = (event) => { console.log("连接关闭:", event.code, event.reason); }; })();
3. 替代第三方库
如果坚持用第三方库,推荐使用Fleck,它是轻量且兼容性更好的WebSocket服务端库:
- 安装NuGet包:
Install-Package Fleck - 示例代码:
using Fleck; class Program { static void Main(string[] args) { var server = new WebSocketServer("ws://127.0.0.1:8080"); server.Start(socket => { socket.OnOpen = () => Console.WriteLine("客户端已连接"); socket.OnMessage = message => Console.WriteLine("收到Token: " + message); socket.OnClose = () => Console.WriteLine("客户端已断开"); socket.OnError = error => Console.WriteLine("错误: " + error); }); Console.ReadKey(true); server.Dispose(); } }
内容的提问来源于stack exchange,提问作者PercivallAkihiko

