none
如何在控制台中编写WebSocket程序?有哪些工具框架可以实现? RRS feed

  • 问题

  • 想要实现通信功能,用WebSocket,但想希望能在非Asp.net环境下独立启动WebSocket服务,但用socket从0实现比较麻烦,有已经实现针对C#的webSocket框架工具么?
    2020年6月5日 3:29

全部回复

  • Hi,

    下面是我写的一个代码示例,这边需要注意的是URL必须要与端口一致。

    首先是控制台应用程序。

     class Program
        {
            public static void Main()
            {
                string ip = "127.0.0.1";
                int port = 8080;
                var server = new TcpListener(IPAddress.Parse(ip), port);
    
                server.Start();
                Console.WriteLine("Server has started on {0}:{1}, Waiting for a connection...", ip, port);
    
                TcpClient client = server.AcceptTcpClient();
                Console.WriteLine("A client connected.");
    
                NetworkStream stream = client.GetStream();
    
                // enter to an infinite cycle to be able to handle every change in stream
                while (true)
                {
                    while (!stream.DataAvailable) ;
                    while (client.Available < 3) ; // match against "get"
    
                    byte[] bytes = new byte[client.Available];
                    stream.Read(bytes, 0, client.Available);
                    string s = Encoding.UTF8.GetString(bytes);
    
                    if (Regex.IsMatch(s, "^GET", RegexOptions.IgnoreCase))
                    {
                        Console.WriteLine("=====Handshaking from client=====\n{0}", s);
    
                        // 1. Obtain the value of the "Sec-WebSocket-Key" request header without any leading or trailing whitespace
                        // 2. Concatenate it with "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" (a special GUID specified by RFC 6455)
                        // 3. Compute SHA-1 and Base64 hash of the new value
                        // 4. Write the hash back as the value of "Sec-WebSocket-Accept" response header in an HTTP response
                        string swk = Regex.Match(s, "Sec-WebSocket-Key: (.*)").Groups[1].Value.Trim();
                        string swka = swk + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
                        byte[] swkaSha1 = System.Security.Cryptography.SHA1.Create().ComputeHash(Encoding.UTF8.GetBytes(swka));
                        string swkaSha1Base64 = Convert.ToBase64String(swkaSha1);
    
                        // HTTP/1.1 defines the sequence CR LF as the end-of-line marker
                        byte[] response = Encoding.UTF8.GetBytes(
                            "HTTP/1.1 101 Switching Protocols\r\n" +
                            "Connection: Upgrade\r\n" +
                            "Upgrade: websocket\r\n" +
                            "Sec-WebSocket-Accept: " + swkaSha1Base64 + "\r\n\r\n");
    
                        stream.Write(response, 0, response.Length);
                    }
                    else
                    {
                        bool fin = (bytes[0] & 0b10000000) != 0,
                            mask = (bytes[1] & 0b10000000) != 0; // must be true, "All messages from the client to the server have this bit set"
    
                        int opcode = bytes[0] & 0b00001111, // expecting 1 - text message
                            msglen = bytes[1] - 128, // & 0111 1111
                            offset = 2;
    
                        if (msglen == 126)
                        {
                            // was ToUInt16(bytes, offset) but the result is incorrect
                            msglen = BitConverter.ToUInt16(new byte[] { bytes[3], bytes[2] }, 0);
                            offset = 4;
                        }
                        else if (msglen == 127)
                        {
                            Console.WriteLine("TODO: msglen == 127, needs qword to store msglen");
                            // i don't really know the byte order, please edit this
                            // msglen = BitConverter.ToUInt64(new byte[] { bytes[5], bytes[4], bytes[3], bytes[2], bytes[9], bytes[8], bytes[7], bytes[6] }, 0);
                            // offset = 10;
                        }
    
                        if (msglen == 0)
                            Console.WriteLine("msglen == 0");
                        else if (mask)
                        {
                            byte[] decoded = new byte[msglen];
                            byte[] masks = new byte[4] { bytes[offset], bytes[offset + 1], bytes[offset + 2], bytes[offset + 3] };
                            offset += 4;
    
                            for (int i = 0; i < msglen; ++i)
                                decoded[i] = (byte)(bytes[offset + i] ^ masks[i % 4]);
    
                            string text = Encoding.UTF8.GetString(decoded);
                            Console.WriteLine("Message received {0}", text);
                        }
                        else
                            Console.WriteLine("mask bit not set");
    
                        Console.WriteLine();
                    }
                }
            }
        }

    html设计:

    <!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">
            function connect() {
                var text = document.getElementById("test1").value;
                var ws = new WebSocket("ws://localhost:8080/service");
                ws.onopen = function () {
                    alert("About to send data");
                    ws.send(text); // I WANT TO SEND THIS MESSAGE TO THE SERVER!!!!!!!!
                    alert("Message sent!");
                };
    
                ws.onmessage = function (evt) {
                    alert("About to receive data");
                    var received_msg = evt.data;
                    alert("Message received = "+received_msg);
                };
                ws.onclose = function () {
                    // websocket is closed.
                    alert("Connection is closed...");
                };
            };
    
    
        </script>
    </head>
    <body style="font-size:xx-large" >
        <div>
        <a href="#" onclick="connect()">Click here to start</a></div>
        <input id="test1" >
    </body>
    </html>

    注意:需要先打开控制台应用程序开启服务端,然后再打开html文件输入文本点击按钮,最后控制台会收到消息。

    这是结果:

    Best Regards,

    Jack


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    2020年6月5日 8:07
    版主