本文介绍了C# HTML5 Websocket 服务器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建一个 C# Websocket 服务器,但我似乎没有让它工作.我现在有一个服务器,它接受 TCPClient,接收来自客户端的 HTTP 请求并尝试发回 HTTP 响应,以便可以完成 HTML5 WebSocket 握手.

I'm trying to create a C# Websocket server but I just don't seem to get it working.I now have a server that accepts the TCPClient, receives the HTTP request from the client and that tries to send back a HTTP response so the HTML5 WebSocket handshake can be completed.

我认为服务器发送给客户端的握手有问题.我阅读了草案(Websocket 76 草案) 表示在握手结束时必须对给出的两个密钥给出响应.此响应由服务器计算.

I believe there is something wrong with my handshake that the server sends to the client.I read the draft (Websocket 76 draft) which states that at the end of the handshake a response has to be given for the two keys that are given. This response gets calculated by the server.

这是我的代码:

static void Main(string[] args)
    {
        int port = 8181;
        IPAddress localAddr = IPAddress.Loopback;

        TcpListener server = new TcpListener(localAddr, port);
        server.Start();

        // Buffer for reading data
        Byte[] receivedBytes = new Byte[256];
        String data = null;

        // Enter the listening loop.
        while (true)
        {
            Console.WriteLine("Waiting for a connection...");

            // Perform a blocking call to accept requests.
            // You could also user server.AcceptSocket() here.
            TcpClient client = server.AcceptTcpClient();
            Console.WriteLine("Connected!
");

            data = null;

            // Get a stream object for reading and writing
            NetworkStream stream = client.GetStream();

            int i;


            // Loop to receive all the data sent by the client.
            while ((i = stream.Read(receivedBytes, 0, receivedBytes.Length)) != 0)
            {
                // Translate data bytes to a ASCII string.
                data = System.Text.Encoding.UTF8.GetString(receivedBytes, 0, i);

                Console.WriteLine("Received:");
                Console.WriteLine(data);
                Byte[] response_token = hashResponse(data);


                string handshake = "HTTP/1.1 101 WebSocket Protocol Handshake
"
                    + "Upgrade: WebSocket
" + "Connection: Upgrade
"
                    + "Sec-WebSocket-Origin: http://localhost
"
                    + "Sec-WebSocket-Location: ws://localhost:8181/websession
"
                    + "
";

                Byte[] writtenBytes = Encoding.UTF8.GetBytes(handshake);

                stream.Write(writtenBytes, 0, writtenBytes.Length);
                stream.Write(response_token, 0, response_token.Length);

                Console.WriteLine("Send:");
                Console.WriteLine(handshake);

                string strHash = Encoding.UTF8.GetString(response_token);
                Console.WriteLine(strHash);
            }
        }
    }

    static Byte[] hashResponse(string receivedData)
    {
        string strDel = "
";
        char[] delimeter = strDel.ToCharArray();

        string Key1 = null;
        string Key2 = null;
        string hash = null;
        MD5 md5 = MD5.Create();

        string[] lines = receivedData.Split(delimeter);
        Key1 = lines[10].Substring(20);
        Key2 = lines[12].Substring(20);
        hash = lines[16];

        Int64 numbersKey1 = Convert.ToInt64(string.Join(null, Regex.Split(Key1, "[^\d]")));
        Int64 numbersKey2 = Convert.ToInt64(string.Join(null, Regex.Split(Key2, "[^\d]")));

        Int64 numberSpaces1 = countSpaces(Key1);
        Int64 numberSpaces2 = countSpaces(Key2);

        int dividedKey1 = (int) (numbersKey1 / numberSpaces1);
        int dividedKey2 = (int) (numbersKey2 / numberSpaces2);

        Byte[] encodedKey1 = Encoding.UTF8.GetBytes(dividedKey1.ToString());
        Byte[] encodedKey2 = Encoding.UTF8.GetBytes(dividedKey2.ToString());
        Byte[] encodedHash = Encoding.UTF8.GetBytes(hash);

        Byte[] combined = Encoding.UTF8.GetBytes(dividedKey1.ToString() + dividedKey2.ToString() + hash);

        Byte[] responseHash = md5.ComputeHash(combined);
        return responseHash;
    }

    static int countSpaces(string key)
    {
        int counter = 0;
        char[] charArray = key.ToCharArray();

        foreach (char c in charArray)
        {
            if (c.Equals(' '))
                counter++;
        }

        return counter;
    }

我用于测试的 HTML 页面(名为 Test.html)由在我的计算机上运行的 apache 网络服务器托管我通过浏览(在 Chrome 中)到 http://localhost/Test.html 来访问它

The HTML page (which is named Test.html) I'm using for testing is hosted by an apache webserver which runs on my computer I access it by browsing (in Chrome) to http://localhost/Test.html

有没有人知道我做错了什么,因为我非常绝望.

Does anyone have a clue what I'm doing wrong because I'm getting quite desperate.

提前致谢

丹尼斯

推荐答案

这是我根据 草稿ietf-hybi-thewebsocketprotocol-00:

using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;

class Program
{
    static void Main(string[] args)
    {
        var listener = new TcpListener(IPAddress.Loopback, 8080);
        listener.Start();
        while (true)
        {
            using (var client = listener.AcceptTcpClient())
            using (var stream = client.GetStream())
            {
                var headers = new Dictionary<string, string>();
                string line = string.Empty;
                while ((line = ReadLine(stream)) != string.Empty)
                {
                    var tokens = line.Split(new char[] { ':' }, 2);
                    if (!string.IsNullOrWhiteSpace(line) && tokens.Length > 1)
                    {
                        headers[tokens[0]] = tokens[1].Trim();
                    }
                }

                var key = new byte[8];
                stream.Read(key, 0, key.Length);

                var key1 = headers["Sec-WebSocket-Key1"];
                var key2 = headers["Sec-WebSocket-Key2"];

                var numbersKey1 = Convert.ToInt64(string.Join(null, Regex.Split(key1, "[^\d]")));
                var numbersKey2 = Convert.ToInt64(string.Join(null, Regex.Split(key2, "[^\d]")));
                var numberSpaces1 = CountSpaces(key1);
                var numberSpaces2 = CountSpaces(key2);

                var part1 = (int)(numbersKey1 / numberSpaces1);
                var part2 = (int)(numbersKey2 / numberSpaces2);

                var result = new List<byte>();
                result.AddRange(GetBigEndianBytes(part1));
                result.AddRange(GetBigEndianBytes(part2));
                result.AddRange(key);

                var response =
                    "HTTP/1.1 101 WebSocket Protocol Handshake" + Environment.NewLine +
                    "Upgrade: WebSocket" + Environment.NewLine +
                    "Connection: Upgrade" + Environment.NewLine +
                    "Sec-WebSocket-Origin: " + headers["Origin"] + Environment.NewLine +
                    "Sec-WebSocket-Location: ws://localhost:8080/websession" + Environment.NewLine +
                    Environment.NewLine;

                var bufferedResponse = Encoding.UTF8.GetBytes(response);
                stream.Write(bufferedResponse, 0, bufferedResponse.Length);
                using (var md5 = MD5.Create())
                {
                    var handshake = md5.ComputeHash(result.ToArray());
                    stream.Write(handshake, 0, handshake.Length);
                }
            }
        }
    }

    static int CountSpaces(string key)
    {
        return key.Length - key.Replace(" ", string.Empty).Length;
    }

    static string ReadLine(Stream stream)
    {
        var sb = new StringBuilder();
        var buffer = new List<byte>();
        while (true)
        {
            buffer.Add((byte)stream.ReadByte());
            var line = Encoding.ASCII.GetString(buffer.ToArray());
            if (line.EndsWith(Environment.NewLine))
            {
                return line.Substring(0, line.Length - 2);
            }
        }
    }

    static byte[] GetBigEndianBytes(int value)
    {
        var bytes = 4;
        var buffer = new byte[bytes];
        int num = bytes - 1;
        for (int i = 0; i < bytes; i++)
        {
            buffer[num - i] = (byte)(value & 0xffL);
            value = value >> 8;
        }
        return buffer;
    }
}

还有一个示例客户端:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <script type="text/javascript">
        var socket = new WebSocket('ws://localhost:8080/websession');
        socket.onopen = function() {
            alert('handshake successfully established. May send data now...');
        };
        socket.onclose = function() {
            alert('connection closed');
        };
    </script>
</head>
<body>
</body>
</html>

这篇关于C# HTML5 Websocket 服务器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-06 18:51