有没有一个已经实现的用于.NET的WebSocket客户端?

54

我想在我的Windows Forms或WPF应用程序中使用WebSocket。是否已经有支持WebSocket的.NET控件实现?或者是否已经有任何开源项目开始处理它?

一个支持WebSocket的Java客户端的开源解决方案也可以帮助我。

11个回答

24

这是将那段Java代码转换为C#的快速首次尝试。不支持SSL模式,且仅进行了少量测试,但这是一个开始。

using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;

public class WebSocket
{
    private Uri mUrl;
    private TcpClient mClient;
    private NetworkStream mStream;
    private bool mHandshakeComplete;
    private Dictionary<string, string> mHeaders;
    
    public WebSocket(Uri url)
    {
        mUrl = url;
        
        string protocol = mUrl.Scheme;
        if (!protocol.Equals("ws") && !protocol.Equals("wss"))
            throw new ArgumentException("Unsupported protocol: " + protocol);
    }
    
    public void SetHeaders(Dictionary<string, string> headers)
    {
        mHeaders = headers;
    }
    
    public void Connect()
    {
        string host = mUrl.DnsSafeHost;
        string path = mUrl.PathAndQuery;
        string origin = "http://" + host;

        mClient = CreateSocket(mUrl);
        mStream = mClient.GetStream();

        int port = ((IPEndPoint)mClient.Client.RemoteEndPoint).Port;
        if (port != 80)
            host = host + ":" + port;

        StringBuilder extraHeaders = new StringBuilder();
        if (mHeaders != null)
        {
            foreach (KeyValuePair<string, string> header in mHeaders)
                extraHeaders.Append(header.Key + ": " + header.Value + "\r\n");
        }

        string request = "GET " + path + " HTTP/1.1\r\n" +
                         "Upgrade: WebSocket\r\n" +
                         "Connection: Upgrade\r\n" +
                         "Host: " + host + "\r\n" +
                         "Origin: " + origin + "\r\n" +
                         extraHeaders.ToString() + "\r\n";
        byte[] sendBuffer = Encoding.UTF8.GetBytes(request);

        mStream.Write(sendBuffer, 0, sendBuffer.Length);

        StreamReader reader = new StreamReader(mStream);
        {
            string header = reader.ReadLine();
            if (!header.Equals("HTTP/1.1 101 Web Socket Protocol Handshake"))
                throw new IOException("Invalid handshake response");

            header = reader.ReadLine();
            if (!header.Equals("Upgrade: WebSocket"))
                throw new IOException("Invalid handshake response");

            header = reader.ReadLine();
            if (!header.Equals("Connection: Upgrade"))
                throw new IOException("Invalid handshake response");
        }

        mHandshakeComplete = true;
    }
    
    public void Send(string str)
    {
        if (!mHandshakeComplete)
            throw new InvalidOperationException("Handshake not complete");

        byte[] sendBuffer = Encoding.UTF8.GetBytes(str);

        mStream.WriteByte(0x00);
        mStream.Write(sendBuffer, 0, sendBuffer.Length);
        mStream.WriteByte(0xff);
        mStream.Flush();
    }

    public string Recv()
    {
        if (!mHandshakeComplete)
            throw new InvalidOperationException("Handshake not complete");

        StringBuilder recvBuffer = new StringBuilder();

        BinaryReader reader = new BinaryReader(mStream);
        byte b = reader.ReadByte();
        if ((b & 0x80) == 0x80)
        {
            // Skip data frame
            int len = 0;
            do
            {
                b = (byte)(reader.ReadByte() & 0x7f);
                len += b * 128;
            } while ((b & 0x80) != 0x80);

            for (int i = 0; i < len; i++)
                reader.ReadByte();
        }
        
        while (true)
        {
            b = reader.ReadByte();
            if (b == 0xff)
                break;

            recvBuffer.Append(b);           
        }

        return recvBuffer.ToString();
    }
    
    public void Close()
    {
        mStream.Dispose();
        mClient.Close();
        mStream = null;
        mClient = null;
    }

    private static TcpClient CreateSocket(Uri url)
    {
        string scheme = url.Scheme;
        string host = url.DnsSafeHost;

        int port = url.Port;
        if (port <= 0)
        {
            if (scheme.Equals("wss"))
                port = 443;
            else if (scheme.Equals("ws"))
                port = 80;
            else
                throw new ArgumentException("Unsupported scheme");
        }

        if (scheme.Equals("wss"))
            throw new NotImplementedException("SSL support not implemented yet");
        else
            return new TcpClient(host, port);
    }
}

6
注意,StringBuilder.Append(byte) 并不是你想象中的那样 -- 它会将字节的文本表示附加到缓冲区中。 使用编码 UTF8 并通过构建字节列表然后将该 byte[] 转换为字符串来实现更好的效果。 - Patrick Linskey
1
+1 对我很有效。我最终修改了 mStream = new SslStream(mClient.GetStream()); 并添加了 mStream.AuthenicateAsClient(host);,这就是 SSL 支持所需的全部内容。 - primo

22

1
我在SuperWebSocket中找不到有关客户端实现的任何信息。 它还在那里吗? - Simon_Weaver
在 SourceCode/mainline/Client 中 - Kerry Jiang
8
SuperWebSocket中的客户端已被拆分为WebSocket4Net:http://websocket4net.codeplex.com/。 - Kerry Jiang
当我尝试使用WebSocket4Net从.NET连接到socket.io时,我看到“debug - destroying non-socket.io upgrade”。我错过了什么? - tofutim

12

5
从文档中可以看到,“仅支持在Windows 8和Windows Server 2012上使用客户端和服务器的公共WebSocket实现”,也就是说,旧版本的Windows系统无法使用WebSocket。 - steve cook

7

5

4

另一个选择:XSockets.Net,已经实现了服务器和客户端。

可以通过以下方式安装服务器:

PM> Install-Package XSockets

或者通过以下方式安装客户端:

PM> Install-Package XSockets.Client

当前版本为:3.0.4

3

1

这是一个相当简单的协议。这里有一个Java实现链接,应该不难转换成C#。如果我有时间做,我会在这里发布...


1

最近,互操作性桥梁和实验室中心发布了WebSockets协议规范的两个草案(使用托管代码)的原型实现:

draft-hixie-thewebsocketprotocol-75draft-hixie-thewebsocketprotocol-76

该原型可以在HTML5实验室找到。我在这篇博客文章中分享了我找到的所有信息(截至目前),以及如何使用WCF完成此操作的代码片段。


1
如果你想要一些更轻量级的东西,可以看看我和一个朋友发布的 C# 服务器: https://github.com/Olivine-Labs/Alchemy-Websockets 它支持原始WebSockets以及Flash WebSockets。 它是为我们的在线游戏构建的,专注于可伸缩性和效率。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接