使用C#连接到websocket(我可以使用JavaScript连接,但C#给出状态代码200错误)

使用C#连接到websocket(我可以使用JavaScript连接,但C#给出状态代码200错误),javascript,c#,websocket,Javascript,C#,Websocket,我是websocket领域的新手 我可以使用以下代码使用JavaScript连接到websocket服务器: var webSocket = new WebSocket(url); 但是对于我的应用程序,我需要使用c#连接到同一台服务器。我使用的代码是: ClientWebSocket webSocket = null; webSocket = new ClientWebSocket(); await webSocket.ConnectAsync(new Uri(url), Cancellat

我是websocket领域的新手

我可以使用以下代码使用JavaScript连接到websocket服务器:

var webSocket = new WebSocket(url);
但是对于我的应用程序,我需要使用c#连接到同一台服务器。我使用的代码是:

ClientWebSocket webSocket = null;
webSocket = new ClientWebSocket();
await webSocket.ConnectAsync(new Uri(url), CancellationToken.None);
代码的第三行导致以下错误:

“当状态代码为101时,服务器返回了状态代码200”

经过一点调查,我意识到服务器在连接过程中无法将http协议切换到websocket协议

我的C#代码有什么愚蠢的地方吗?或者服务器出了问题。我没有任何访问服务器的权限,因为我使用的url是第三方的


关于这个问题,您能给我一些建议吗?

如果您连接到WebSocket客户端,并得到HTTP 200作为响应,则表示您可能连接到了错误的位置(主机、路径和/或端口)

基本上,您正在连接到一个不理解WebSocket需求的普通HTTP端点,它只是返回“OK”响应(HTTP 200)。WebSocket服务器可能在同一服务器的另一个端口或路径中运行


检查您的URL。

Websocket URL应该以
ws://
wss://
开头,后者是安全的Websocket。

不太确定WebSocketSharp nuget包发生了什么,但是我注意到现在是nuget repo中最相关的结果。我花了一些时间才意识到,
Connect()
现在正在返回
Task
,希望这个示例对某人有用:

using System;
using System.Threading.Tasks;
using WebSocketSharp;

namespace Example
{
    class Program
    {
        private static void Main(string[] args)
        {
            using (var ws = new WebSocket(url: "ws://localhost:1337", onMessage: OnMessage, onError: OnError))
            {
                ws.Connect().Wait();
                ws.Send("Hey, Server!").Wait();
                Console.ReadKey(true);
            }
        }

        private static Task OnError(ErrorEventArgs errorEventArgs)
        {
            Console.Write("Error: {0}, Exception: {1}", errorEventArgs.Message, errorEventArgs.Exception);
            return Task.FromResult(0);
        }

        private static Task OnMessage(MessageEventArgs messageEventArgs)
        {
            Console.Write("Message received: {0}", messageEventArgs.Text.ReadToEnd());
            return Task.FromResult(0);
        }
    }
}

由于WebsocketSharp与.NET内核不兼容,我建议使用。 下面是一些示例代码

static async Task Main(string[] args)
{
    var url = new Uri("wss://echo.websocket.org");
    var exitEvent = new ManualResetEvent(false);

    using (var client = new WebsocketClient(url))
    {
        client.MessageReceived.Subscribe(msg => Console.WriteLine($"Message: {msg}"));
        await client.Start();

        await client.Send("Echo");

        exitEvent.WaitOne();
    }

    Console.ReadLine();
}

确保使用
ManualResetEvent
。否则它就不能工作。

上面提到的所有库都是包装器。执行此操作的.Net Framework类是

TL;博士:

在循环中使用
ReceiveAsync()
,直到收到
Close
帧或取消
CancellationToken
为止。这就是你收到信息的方式。发送是直接的,只需
sendsync()
。不要在
CloseOutputAsync()
之前使用
CloseAsync()
——因为您想先停止接收循环。否则-要么
CloseAsync()
将挂起,要么如果使用
CancellationToken
退出
ReceiveAsync()
CloseAsync()
将抛出

我从中学到了很多

完整答案:

使用Dotnet客户端,这里有一个从我的实际代码中剪下的示例,演示如何进行握手。最重要的一点是,大多数人都不了解这个东西是如何运作的,那就是当收到一条消息时,没有什么神奇的事情发生。你自己创造它。怎么做

您只需在一个循环中执行
ReceiveAsync()
,该循环在接收到特殊的
Close
帧时结束。因此,当您想要断开连接时,您必须告诉服务器您用
CloseOutputAsync
关闭,这样它将用类似的
Cloce
帧回复您的客户端,这样它就可以结束接收

我的代码示例仅说明了最基本的外部传输机制。因此,您可以发送和接收原始二进制消息。此时,您无法判断特定服务器响应是否与您发送的特定请求相关。在编码/解码消息后,您必须自己匹配它们。使用任何序列化工具,但许多加密货币市场使用谷歌的协议缓冲区。名字说明了一切;)

对于匹配,可以使用任何唯一的随机数据。您需要令牌,在C#中,我使用
Guid
class来实现这一点

然后,我使用请求/响应匹配使请求在不依赖于事件的情况下工作。
SendRequest()
方法等待匹配的响应,或者。。。连接已关闭。非常方便,可以让代码比基于事件的方法更具可读性。当然,您仍然可以对收到的消息调用事件,只需确保它们与任何需要响应的请求都不匹配

哦,对于我的
async
方法中的等待,我使用
SemaphoreSlim
。每个请求都将自己的信号量放在一个特殊的字典中,当我得到响应时,我通过响应令牌找到条目,释放信号量,处理它,从字典中删除。看起来很复杂,但实际上很简单

使用系统;
使用System.Collections.Generic;
使用System.IO;
使用System.Linq;
使用System.Net.WebSockets;
使用系统线程;
使用System.Threading.Tasks;
名称空间示例{
公共类WsClient:IDisposable{
public int ReceiveBufferSize{get;set;}=8192;
公共异步任务ConnectAsync(字符串url){
如果(WS!=null){
if(WS.State==WebSocketState.Open)返回;
else-WS.Dispose();
}
WS=新客户端WebSocket();
如果(CTS!=null)CTS.Dispose();
CTS=新的CancellationTokenSource();
等待WS.ConnectAsync(新的Uri(url)、CTS.Token);
wait Task.Factory.StartNew(ReceiveLoop、CTS.Token、TaskCreationOptions.longlunning、TaskScheduler.Default);
}
公共异步任务DisconnectAsync(){
如果(WS为null)返回;
//TODO:请求清理代码,依赖于子协议。
if(WS.State==WebSocketState.Open){
CTS.CancelAfter(TimeSpan.FromSeconds(2));
等待WS.CloseOutputAsync(WebSocketCloseStatus.Empty,”,CancellationToken.None);
等待WS.CloseAsync(WebSocketCloseStatus.NormalClose,“,CancellationToken.None);
}
WS.Dispose();
WS=null;
CTS.Dispose();
CTS=null;
}
专用异步任务ReceiveLoop(){