Tạo một ví dụ về WebSocket “Hello World”


85

Tôi không hiểu tại sao tôi không thể làm cho đoạn mã sau hoạt động. Tôi muốn kết nối với JavaScript với ứng dụng bảng điều khiển máy chủ của mình. Và sau đó gửi dữ liệu đến máy chủ.

Đây là mã máy chủ:

    static void Main(string[] args)
    {            
        TcpListener server = new TcpListener(IPAddress.Parse("127.0.0.1"), 9998);
        server.Start();
        var client = server.AcceptTcpClient();
        var stream = client.GetStream();

        while (true)
        {
            var buffer = new byte[1024]; 
            // wait for data to be received
            var bytesRead = stream.Read(buffer, 0, buffer.Length);                
            var r = System.Text.Encoding.UTF8.GetString(buffer);
            // write received data to the console
            Console.WriteLine(r.Substring(0, bytesRead));
        }
    }

và đây là JavaScript:

        var ws = new WebSocket("ws://localhost:9998/service");
        ws.onopen = function () {
            ws.send("Hello World"); // I WANT TO SEND THIS MESSAGE TO THE SERVER!!!!!!!!
        };

        ws.onmessage = function (evt) {
            var received_msg = evt.data;
            alert("Message is received...");
        };
        ws.onclose = function () {
            // websocket is closed.
            alert("Connection is closed...");
        };

Khi tôi chạy mã đó, điều này sẽ xảy ra:

Lưu ý rằng khi tôi chạy JavaScript, máy chủ chấp nhận và thiết lập kết nối thành công. JavaScript không thể gửi dữ liệu. Bất cứ khi nào tôi đặt phương thức gửi, nó sẽ không gửi mặc dù kết nối đã được thiết lập. Làm thế nào tôi có thể làm cho nó hoạt động?


9
"Câu hỏi" này dường như không còn là một câu hỏi nữa và do đó không thực sự phù hợp với định dạng của StackOverflow. FWIW, thông điệp của khách hàng không được mã hóa,bị che (làm xáo trộn) bởi XOR'ing chống lại một giá trị ngẫu nhiên được truyền như một phần của khung. Chi tiết giao thức này tồn tại để tránh các cuộc tấn công đầu độc vào máy chủ proxy có thể hiểu nhầm lưu lượng truy cập.
EricLaw

1
cảm ơn, câu trả lời này rất hữu ích :) này, chỉ một điều, đây có phải là "static private string Guid =" 258EAFA5-E914-47DA-95CA-C5AB0DC85B11 ";" điều luôn luôn không đổi? nếu không, tôi có thể lấy các giá trị này ở đâu?
Charmie

1
i nhận điều này: "Một máy chủ không phải che giấu bất kỳ khung hình mà nó sẽ gửi cho khách hàng"
Charmie

5
Bạn có lẽ nên để nguyên câu hỏi ban đầu. Mục đích của các câu hỏi là trình bày vấn đề, không phải giải pháp. Các câu trả lời, như bạn có thể đoán, là các giải pháp.
Kehlan Krumme

1
Tại sao url WebSocket kết thúc bằng '/ service' (ws: // localhost: 8080 / service)? Tại sao không chỉ là 'ws: // localhost: 8080'?
andree

Câu trả lời:


72

WebSockets là giao thức dựa trên kết nối dòng TCP. Mặc dù WebSockets là giao thức dựa trên Message.

Nếu bạn muốn triển khai giao thức của riêng mình thì tôi khuyên bạn nên sử dụng đặc điểm kỹ thuật mới nhất và ổn định (cho 18/04/12) RFC 6455 . Đặc điểm kỹ thuật này chứa tất cả thông tin cần thiết liên quan đến bắt tay và đóng khung. Cũng như hầu hết các mô tả về các tình huống hoạt động từ phía trình duyệt cũng như từ phía máy chủ. Bạn thực sự nên làm theo những gì khuyến nghị cho biết về phía máy chủ trong quá trình triển khai mã của bạn.

Nói một cách ngắn gọn, tôi sẽ mô tả cách làm việc với WebSockets như thế này:

  1. Tạo Socket máy chủ (System.Net.Sockets) liên kết nó với một cổng cụ thể và tiếp tục lắng nghe với việc chấp nhận không đồng bộ các kết nối. Đại loại vậy:

    Socket serverSocket = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
    serverSocket.Bind (IPEndPoint mới (IPAddress.Any, 8080));
    serverSocket.Listen (128);
    serverSocket.BeginAccept (null, 0, OnAccept, null);
  2. Bạn nên có chức năng chấp nhận "OnAccept" sẽ thực hiện bắt tay. Trong tương lai, nó phải nằm trong một luồng khác nếu hệ thống có khả năng xử lý lượng kết nối khổng lồ mỗi giây.

    private void OnAccept (kết quả IAsyncResult) {
    thử {
        Socket client = null;
        if (serverSocket! = null && serverSocket.IsBound) {
            client = serverSocket.EndAccept (kết quả);
        }
        if (client! = null) {
            / * Bắt tay và quản lý ClientSocket * /
        }
    } catch (ngoại lệ SocketException) {
    
    } cuối cùng {
        if (serverSocket! = null && serverSocket.IsBound) {
            serverSocket.BeginAccept (null, 0, OnAccept, null);
        }
    }
    }
  3. Sau khi kết nối được thiết lập, bạn phải thực hiện bắt tay . Dựa trên đặc điểm kỹ thuật 1.3 Mở Bắt tay , sau khi kết nối được thiết lập, bạn sẽ nhận được yêu cầu HTTP cơ bản với một số thông tin. Thí dụ:

    NHẬN / trò chuyện HTTP / 1.1
    Máy chủ: server.example.com
    Nâng cấp: websocket
    Kết nối: Nâng cấp
    Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ ==
    Nguồn gốc: http://example.com
    Sec-WebSocket-Protocol: trò chuyện, superchat
    Sec-WebSocket-Phiên bản: 13

    Ví dụ này dựa trên phiên bản của giao thức 13. Hãy nhớ rằng các phiên bản cũ hơn có một số khác biệt nhưng hầu hết các phiên bản mới nhất đều tương thích chéo. Các trình duyệt khác nhau có thể gửi cho bạn một số dữ liệu bổ sung. Ví dụ: chi tiết Trình duyệt và hệ điều hành, bộ nhớ cache và những thứ khác.

    Dựa trên các chi tiết bắt tay được cung cấp, bạn phải tạo các dòng trả lời, chúng hầu như giống nhau, nhưng sẽ chứa Accpet-Key, dựa trên Sec-WebSocket-Key được cung cấp. Trong đặc tả 1.3, nó được mô tả rõ ràng cách tạo khóa phản hồi. Đây là chức năng của tôi mà tôi đã sử dụng cho V13:

    static private string Guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
    chuỗi riêng AcceptKey (khóa chuỗi tham chiếu) {
        string longKey = key + Guid;
        SHA1 sha1 = SHA1CryptoServiceProvider.Create ();
        byte [] hashBytes = sha1.ComputeHash (System.Text.Encoding.ASCII.GetBytes (longKey));
        trả về Convert.ToBase64String (hashBytes);
    }
    

    Câu trả lời bắt tay có dạng như sau:

    Giao thức chuyển đổi HTTP / 1.1 101
    Nâng cấp: websocket
    Kết nối: Nâng cấp
    Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK + xOo =

    Nhưng khóa accept phải là khóa được tạo dựa trên khóa được cung cấp từ máy khách và phương thức AcceptKey mà tôi đã cung cấp trước đây. Ngoài ra, hãy đảm bảo rằng sau ký tự cuối cùng của phím chấp nhận, bạn đặt hai dòng mới "\ r \ n \ r \ n".

  4. Sau khi câu trả lời bắt tay được gửi từ máy chủ, máy khách sẽ kích hoạt chức năng " onopen ", nghĩa là bạn có thể gửi tin nhắn sau đó.
  5. Tin nhắn không được gửi ở định dạng thô, nhưng chúng có Khung dữ liệu . Và từ máy khách đến máy chủ cũng thực hiện việc tạo mặt nạ cho dữ liệu dựa trên 4 byte được cung cấp trong tiêu đề thư. Mặc dù từ máy chủ đến máy khách, bạn không cần áp dụng tính năng che trên dữ liệu. Đọc phần 5. Khung dữ liệu trong đặc tả. Đây là sao chép-dán từ triển khai của riêng tôi. Nó không phải là mã sẵn sàng để sử dụng và phải được sửa đổi, tôi đăng nó chỉ để đưa ra ý tưởng và logic tổng thể của việc đọc / ghi với khung WebSocket. Đi đến liên kết này .
  6. Sau khi thực hiện đóng khung, hãy đảm bảo rằng bạn nhận dữ liệu đúng cách bằng cách sử dụng các ổ cắm. Ví dụ để ngăn một số thông báo được hợp nhất thành một, vì TCP vẫn là giao thức dựa trên luồng. Điều đó có nghĩa là bạn CHỈ phải đọc số lượng byte cụ thể. Độ dài của thông báo luôn dựa trên tiêu đề và được cung cấp chi tiết độ dài dữ liệu trong tiêu đề của chính nó. Vì vậy, khi bạn nhận dữ liệu từ Socket, trước tiên hãy nhận 2 byte, lấy thông tin chi tiết từ tiêu đề dựa trên đặc điểm kỹ thuật Framing, sau đó nếu mặt nạ cung cấp 4 byte khác và sau đó độ dài có thể là 1, 4 hoặc 8 byte dựa trên độ dài của dữ liệu. Và sau khi dữ liệu nó tự. Sau khi bạn đọc nó, hãy áp dụng thao tác duyệt và dữ liệu tin nhắn của bạn đã sẵn sàng để sử dụng.
  7. Bạn có thể muốn sử dụng một số Giao thức dữ liệu , tôi khuyên bạn nên sử dụng JSON do tiết kiệm lưu lượng truy cập và dễ sử dụng ở phía máy khách trong JavaScript. Đối với phía máy chủ, bạn có thể muốn kiểm tra một số trình phân tích cú pháp. Có rất nhiều trong số chúng, google có thể thực sự hữu ích.

Việc triển khai giao thức WebSockets của riêng mình chắc chắn có một số lợi ích và trải nghiệm tuyệt vời mà bạn nhận được cũng như tự kiểm soát giao thức. Nhưng bạn phải dành một chút thời gian để thực hiện và đảm bảo rằng việc triển khai đó có độ tin cậy cao.

Đồng thời, bạn có thể có một cái nhìn sẵn sàng để sử dụng các giải pháp mà google (một lần nữa) có đủ.


Tôi đoán tôi đang mắc kẹt trong việc bắt tay. khi nhận được kết nối mới, tôi phải gửi cho khách hàng mã băm sha1 của khóa dài cộng với khóa ngắn phải không?
Tono Nam

Tôi đã bổ sung thêm thông tin trong phần 3. Nó mô tả chi tiết hơn về quá trình bắt tay từ phía máy chủ.
moka

1
Ngoài ra, hãy đảm bảo rằng nếu các giao thức yêu cầu được cung cấp, hãy sử dụng tương tự để đáp ứng cho dòng Sec-WebSocket-Protocol. Nhưng chỉ khi có được cung cấp theo yêu cầu. Cũng như bạn không cần Phiên bản để phản hồi. Và thêm một NewLine khác vào cuối. Đồng thời gửi toàn bộ chuỗi phản hồi được mã hóa bằng UTF8: Encoding.UTF8.GetBytes (responseBytes)
moka

Chúng tôi thân nhau. Cảm ơn rất nhiều vì sự giúp đỡ. Tôi có thể gửi tin nhắn ngay bây giờ nhưng tin nhắn đã được mã hóa. Hãy xem bản chỉnh sửa của tôi mà tôi sẽ sớm bắt đầu thực hiện ...
Tono Nam

Bạn phải triển khai khung dữ liệu, đây là điều tôi tin là phức tạp nhất trong việc triển khai giao thức WebSockets. Tôi sẽ thêm mã copy-paste từ quá trình triển khai của mình vào bài đăng, nhưng hãy đảm bảo rằng bạn chỉnh sửa nó, vì nó có một số thứ cần thay đổi, nhưng nhìn chung là đưa ra ý tưởng và logic làm việc với khung.
moka

9

(Thay mặt OP đăng câu trả lời) .

Tôi có thể gửi dữ liệu ngay bây giờ. Đây là phiên bản chương trình mới của tôi nhờ câu trả lời của bạn và mã của @Maksims Mihejevs.

Người phục vụ

using System;
using System.Net.Sockets;
using System.Net;
using System.Security.Cryptography;
using System.Threading;

namespace ConsoleApplication1
{
    class Program
    {
        static Socket serverSocket = new Socket(AddressFamily.InterNetwork, 
        SocketType.Stream, ProtocolType.IP);
        static private string guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";

        static void Main(string[] args)
        {            
            serverSocket.Bind(new IPEndPoint(IPAddress.Any, 8080));
            serverSocket.Listen(128);
            serverSocket.BeginAccept(null, 0, OnAccept, null);            
            Console.Read();
        }

        private static void OnAccept(IAsyncResult result)
        {
            byte[] buffer = new byte[1024];
            try
            {
                Socket client = null;
                string headerResponse = "";
                if (serverSocket != null && serverSocket.IsBound)
                {
                    client = serverSocket.EndAccept(result);
                    var i = client.Receive(buffer);
                    headerResponse = (System.Text.Encoding.UTF8.GetString(buffer)).Substring(0,i);
                    // write received data to the console
                    Console.WriteLine(headerResponse);

                }
                if (client != null)
                {
                    /* Handshaking and managing ClientSocket */

                    var key = headerResponse.Replace("ey:", "`")
                              .Split('`')[1]                     // dGhlIHNhbXBsZSBub25jZQ== \r\n .......
                              .Replace("\r", "").Split('\n')[0]  // dGhlIHNhbXBsZSBub25jZQ==
                              .Trim();

                    // key should now equal dGhlIHNhbXBsZSBub25jZQ==
                    var test1 = AcceptKey(ref key);

                    var newLine = "\r\n";

                    var response = "HTTP/1.1 101 Switching Protocols" + newLine
                         + "Upgrade: websocket" + newLine
                         + "Connection: Upgrade" + newLine
                         + "Sec-WebSocket-Accept: " + test1 + newLine + newLine
                         //+ "Sec-WebSocket-Protocol: chat, superchat" + newLine
                         //+ "Sec-WebSocket-Version: 13" + newLine
                         ;

                    // which one should I use? none of them fires the onopen method
                    client.Send(System.Text.Encoding.UTF8.GetBytes(response));

                    var i = client.Receive(buffer); // wait for client to send a message

                    // once the message is received decode it in different formats
                    Console.WriteLine(Convert.ToBase64String(buffer).Substring(0, i));                    

                    Console.WriteLine("\n\nPress enter to send data to client");
                    Console.Read();

                    var subA = SubArray<byte>(buffer, 0, i);
                    client.Send(subA);
                    Thread.Sleep(10000);//wait for message to be send


                }
            }
            catch (SocketException exception)
            {
                throw exception;
            }
            finally
            {
                if (serverSocket != null && serverSocket.IsBound)
                {
                    serverSocket.BeginAccept(null, 0, OnAccept, null);
                }
            }
        }

        public static T[] SubArray<T>(T[] data, int index, int length)
        {
            T[] result = new T[length];
            Array.Copy(data, index, result, 0, length);
            return result;
        }

        private static string AcceptKey(ref string key)
        {
            string longKey = key + guid;
            byte[] hashBytes = ComputeHash(longKey);
            return Convert.ToBase64String(hashBytes);
        }

        static SHA1 sha1 = SHA1CryptoServiceProvider.Create();
        private static byte[] ComputeHash(string str)
        {
            return sha1.ComputeHash(System.Text.Encoding.ASCII.GetBytes(str));
        }
    }
}

JavaScript:

<!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 ws = new WebSocket("ws://localhost:8080/service");
            ws.onopen = function () {
                alert("About to send data");
                ws.send("Hello World"); // 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>
</body>
</html>

Khi tôi chạy mã đó, tôi có thể gửi và nhận dữ liệu từ cả máy khách và máy chủ. Vấn đề duy nhất là các tin nhắn được mã hóa khi chúng đến máy chủ. Dưới đây là các bước về cách chương trình chạy:

nhập mô tả hình ảnh ở đây

Lưu ý cách mã hóa tin nhắn từ máy khách.


2
Có điều gì đó không ổn với Ví dụ của bạn, Khi tôi nhấn enter Kết nối sẽ bị đóng.
Richard Aguirre,

@RichardAguirre: Tôi đã đăng bài này thay mặt OP (xem dòng đầu tiên của câu trả lời) - hiện tại họ sẽ không được thông báo về tin nhắn của bạn. Bạn có thể thử ping họ dưới câu hỏi, nhưng họ có thể cần nhiều chi tiết hơn thế.
halfer

6

WebSockets được thực hiện với một giao thức liên quan đến bắt tay giữa máy khách và máy chủ . Tôi không tưởng tượng chúng hoạt động giống như những ổ cắm bình thường. Đọc giao thức và yêu cầu ứng dụng của bạn nói chuyện với nó. Ngoài ra, hãy sử dụng thư viện WebSocket hiện có hoặc .Net4.5beta có API WebSocket .


Tất nhiên chúng hoạt động rất giống các ổ cắm thông thường. Socket ở cấp thấp hơn giao thức ứng dụng và như vậy, không phụ thuộc vào nó. Điều đó có nghĩa là bạn có thể chạy FTP, SMTP, HTTP, WebSockets, v.v. trên một ổ cắm. Người thực hiện phải đảm bảo rằng cô ấy tuân theo đúng giao thức hoặc không ai có thể nói chuyện với máy chủ.
SRM

4

Tôi không thể tìm thấy một ví dụ làm việc đơn giản ở bất kỳ đâu (kể từ ngày 19 tháng 1), vì vậy đây là phiên bản cập nhật. Tôi có phiên bản chrome 71.0.3578.98.

Máy chủ C # Websocket:

using System;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Security.Cryptography;

namespace WebSocketServer
{
    class Program
    {
    static Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
    static private string guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";

    static void Main(string[] args)
    {
        serverSocket.Bind(new IPEndPoint(IPAddress.Any, 8080));
        serverSocket.Listen(1); //just one socket
        serverSocket.BeginAccept(null, 0, OnAccept, null);
        Console.Read();
    }

    private static void OnAccept(IAsyncResult result)
    {
        byte[] buffer = new byte[1024];
        try
        {
            Socket client = null;
            string headerResponse = "";
            if (serverSocket != null && serverSocket.IsBound)
            {
                client = serverSocket.EndAccept(result);
                var i = client.Receive(buffer);
                headerResponse = (System.Text.Encoding.UTF8.GetString(buffer)).Substring(0, i);
                // write received data to the console
                Console.WriteLine(headerResponse);
                Console.WriteLine("=====================");
            }
            if (client != null)
            {
                /* Handshaking and managing ClientSocket */
                var key = headerResponse.Replace("ey:", "`")
                          .Split('`')[1]                     // dGhlIHNhbXBsZSBub25jZQ== \r\n .......
                          .Replace("\r", "").Split('\n')[0]  // dGhlIHNhbXBsZSBub25jZQ==
                          .Trim();

                // key should now equal dGhlIHNhbXBsZSBub25jZQ==
                var test1 = AcceptKey(ref key);

                var newLine = "\r\n";

                var response = "HTTP/1.1 101 Switching Protocols" + newLine
                     + "Upgrade: websocket" + newLine
                     + "Connection: Upgrade" + newLine
                     + "Sec-WebSocket-Accept: " + test1 + newLine + newLine
                     //+ "Sec-WebSocket-Protocol: chat, superchat" + newLine
                     //+ "Sec-WebSocket-Version: 13" + newLine
                     ;

                client.Send(System.Text.Encoding.UTF8.GetBytes(response));
                var i = client.Receive(buffer); // wait for client to send a message
                string browserSent = GetDecodedData(buffer, i);
                Console.WriteLine("BrowserSent: " + browserSent);

                Console.WriteLine("=====================");
                //now send message to client
                client.Send(GetFrameFromString("This is message from server to client."));
                System.Threading.Thread.Sleep(10000);//wait for message to be sent
            }
        }
        catch (SocketException exception)
        {
            throw exception;
        }
        finally
        {
            if (serverSocket != null && serverSocket.IsBound)
            {
                serverSocket.BeginAccept(null, 0, OnAccept, null);
            }
        }
    }

    public static T[] SubArray<T>(T[] data, int index, int length)
    {
        T[] result = new T[length];
        Array.Copy(data, index, result, 0, length);
        return result;
    }

    private static string AcceptKey(ref string key)
    {
        string longKey = key + guid;
        byte[] hashBytes = ComputeHash(longKey);
        return Convert.ToBase64String(hashBytes);
    }

    static SHA1 sha1 = SHA1CryptoServiceProvider.Create();
    private static byte[] ComputeHash(string str)
    {
        return sha1.ComputeHash(System.Text.Encoding.ASCII.GetBytes(str));
    }

    //Needed to decode frame
    public static string GetDecodedData(byte[] buffer, int length)
    {
        byte b = buffer[1];
        int dataLength = 0;
        int totalLength = 0;
        int keyIndex = 0;

        if (b - 128 <= 125)
        {
            dataLength = b - 128;
            keyIndex = 2;
            totalLength = dataLength + 6;
        }

        if (b - 128 == 126)
        {
            dataLength = BitConverter.ToInt16(new byte[] { buffer[3], buffer[2] }, 0);
            keyIndex = 4;
            totalLength = dataLength + 8;
        }

        if (b - 128 == 127)
        {
            dataLength = (int)BitConverter.ToInt64(new byte[] { buffer[9], buffer[8], buffer[7], buffer[6], buffer[5], buffer[4], buffer[3], buffer[2] }, 0);
            keyIndex = 10;
            totalLength = dataLength + 14;
        }

        if (totalLength > length)
            throw new Exception("The buffer length is small than the data length");

        byte[] key = new byte[] { buffer[keyIndex], buffer[keyIndex + 1], buffer[keyIndex + 2], buffer[keyIndex + 3] };

        int dataIndex = keyIndex + 4;
        int count = 0;
        for (int i = dataIndex; i < totalLength; i++)
        {
            buffer[i] = (byte)(buffer[i] ^ key[count % 4]);
            count++;
        }

        return Encoding.ASCII.GetString(buffer, dataIndex, dataLength);
    }

    //function to create  frames to send to client 
    /// <summary>
    /// Enum for opcode types
    /// </summary>
    public enum EOpcodeType
    {
        /* Denotes a continuation code */
        Fragment = 0,

        /* Denotes a text code */
        Text = 1,

        /* Denotes a binary code */
        Binary = 2,

        /* Denotes a closed connection */
        ClosedConnection = 8,

        /* Denotes a ping*/
        Ping = 9,

        /* Denotes a pong */
        Pong = 10
    }

    /// <summary>Gets an encoded websocket frame to send to a client from a string</summary>
    /// <param name="Message">The message to encode into the frame</param>
    /// <param name="Opcode">The opcode of the frame</param>
    /// <returns>Byte array in form of a websocket frame</returns>
    public static byte[] GetFrameFromString(string Message, EOpcodeType Opcode = EOpcodeType.Text)
    {
        byte[] response;
        byte[] bytesRaw = Encoding.Default.GetBytes(Message);
        byte[] frame = new byte[10];

        int indexStartRawData = -1;
        int length = bytesRaw.Length;

        frame[0] = (byte)(128 + (int)Opcode);
        if (length <= 125)
        {
            frame[1] = (byte)length;
            indexStartRawData = 2;
        }
        else if (length >= 126 && length <= 65535)
        {
            frame[1] = (byte)126;
            frame[2] = (byte)((length >> 8) & 255);
            frame[3] = (byte)(length & 255);
            indexStartRawData = 4;
        }
        else
        {
            frame[1] = (byte)127;
            frame[2] = (byte)((length >> 56) & 255);
            frame[3] = (byte)((length >> 48) & 255);
            frame[4] = (byte)((length >> 40) & 255);
            frame[5] = (byte)((length >> 32) & 255);
            frame[6] = (byte)((length >> 24) & 255);
            frame[7] = (byte)((length >> 16) & 255);
            frame[8] = (byte)((length >> 8) & 255);
            frame[9] = (byte)(length & 255);

            indexStartRawData = 10;
        }

        response = new byte[indexStartRawData + length];

        int i, reponseIdx = 0;

        //Add the frame bytes to the reponse
        for (i = 0; i < indexStartRawData; i++)
        {
            response[reponseIdx] = frame[i];
            reponseIdx++;
        }

        //Add the data bytes to the response
        for (i = 0; i < length; i++)
        {
            response[reponseIdx] = bytesRaw[i];
            reponseIdx++;
        }

        return response;
    }
}
}

Máy khách html và javascript:

<!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.send("Hi there from browser.");
        };
		socket.onmessage = function (evt) {
                //alert("About to receive data");
                var received_msg = evt.data;
                alert("Message received = "+received_msg);
            };
        socket.onclose = function() {
            alert('connection closed');
        };
    </script>
</head>
<body>
</body>
</html>


3

Vấn đề

Vì bạn đang sử dụng WebSocket, người chi tiêu là đúng. Sau khi nhận được dữ liệu ban đầu từ WebSocket, bạn cần gửi thông điệp bắt tay từ máy chủ C # trước khi có thêm thông tin.

HTTP/1.1 101 Web Socket Protocol Handshake
Upgrade: websocket
Connection: Upgrade
WebSocket-Origin: example
WebSocket-Location: something.here
WebSocket-Protocol: 13

Một cái gì đó dọc theo những dòng đó.

Bạn có thể thực hiện thêm một số nghiên cứu về cách hoạt động của WebSocket trên w3 hoặc google.

Liên kết và Tài nguyên

Đây là đặc tả giao thức: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76#section-1.3

Danh sách các ví dụ làm việc:


Ngoài ra, tôi đang sử dụng mã hóa UTF8. Tôi có nên sử dụng một mã khác như ASCII không?
Tono Nam

@TonoNam: Theo như tôi biết, mã hóa UTF8 là chính xác - mặc dù tôi không phải là chuyên gia HTML5, vì vậy tôi không biết chắc chắn.
caesay

Tôi đã làm cho nó hoạt động với safari !!! Tôi cần nó để làm cho nó hoạt động với google chrome. Tất cả các ví dụ đều kết nối nhưng không ai trong số chúng gửi dữ liệu thành công. Tôi sẽ tiếp tục cố gắng. Cảm ơn rất nhiều vì sự giúp đỡ!
Tono Nam

Tất nhiên .... Nếu tôi vẫn không hiểu, tôi sẽ biến câu hỏi này thành một câu hỏi thưởng! Tôi thực sự tò mò muốn xem điều này hoạt động. Cảm ơn sự giúp đỡ
Tono Nam

Liên kết đặc tả giao thức của bạn đã lỗi thời. Safari vẫn sử dụng điều này nhưng các trình duyệt khác đã chuyển sang RFC 6455 không tương thích . Ngoài ra, mặc dù bạn chính xác rằng kết nối ban đầu yêu cầu một số thương lượng, các thông báo khác thì không.
simonc
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.