Creazione di un esempio WebSocket "Hello World"


86

Non capisco perché non riesco a far funzionare il seguente codice. Voglio connettermi con JavaScript alla mia applicazione della console del server. E poi invia i dati al server.

Ecco il codice del server:

    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));
        }
    }

ed ecco il 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...");
        };

Quando eseguo quel codice, ecco cosa succede:

Notare che quando eseguo JavaScript il server accetta e stabilisce con successo una connessione. Tuttavia, JavaScript non è in grado di inviare dati. Ogni volta che inserisco il metodo di invio, non verrà inviato anche se viene stabilita una connessione. Come posso farlo funzionare?


10
Questa "domanda" non sembra più essere una domanda e quindi non è realmente adatta al formato di StackOverflow. FWIW, il messaggio del client non è crittografato è mascherato (offuscato) da XOR'ing contro un valore casuale che viene trasmesso come parte del frame. Questo dettaglio del protocollo esiste per evitare attacchi di avvelenamento contro server proxy che potrebbero fraintendere il traffico.
EricLaw

2
grazie, questa risposta è molto utile :) hey, solo una cosa, è questa "static private string guid =" 258EAFA5-E914-47DA-95CA-C5AB0DC85B11 ";" cosa è sempre costante? in caso contrario, dove posso ottenere questi valori?
Charmie

2
ho capito: "Un server non deve mascherare alcun frame che invia al client"
Charmie

6
Probabilmente avresti dovuto lasciare intatta la domanda originale. Lo scopo delle domande è presentare il problema, non la soluzione. Le risposte, come avresti potuto intuire, sono per le soluzioni.
Kehlan Krumme

2
Perché l'URL di WebSocket termina con "/ service" (ws: // localhost: 8080 / service)? Perché non solo "ws: // localhost: 8080"?
andree

Risposte:


72

WebSocket è un protocollo che si basa sulla connessione in streaming TCP. Sebbene WebSocket sia un protocollo basato sui messaggi.

Se desideri implementare il tuo protocollo, ti consiglio di utilizzare la specifica più recente e stabile (per il 18/04/12) RFC 6455 . Questa specifica contiene tutte le informazioni necessarie riguardanti la stretta di mano e l'inquadratura. Inoltre la maggior parte delle descrizioni sugli scenari di comportamento dal lato browser e dal lato server. Si consiglia vivamente di seguire le raccomandazioni fornite in merito al lato server durante l'implementazione del codice.

In poche parole, descriverei lavorare con WebSocket in questo modo:

  1. Crea server Socket (System.Net.Sockets) associandolo a una porta specifica e continua ad ascoltare con l'accettazione asincrona delle connessioni. Qualcosa del genere:

    Socket serverSocket = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
    serverSocket.Bind (nuovo IPEndPoint (IPAddress.Any, 8080));
    serverSocket.Listen (128);
    serverSocket.BeginAccept (null, 0, OnAccept, null);
  2. Dovresti avere la funzione di accettazione "OnAccept" che implementerà l'handshake. In futuro deve essere in un altro thread se il sistema è destinato a gestire un'enorme quantità di connessioni al secondo.

    private void OnAccept (risultato IAsyncResult) {
    provare {
        Client socket = null;
        if (serverSocket! = null && serverSocket.IsBound) {
            client = serverSocket.EndAccept (risultato);
        }
        if (client! = null) {
            / * Handshaking e gestione di ClientSocket * /
        }
    } catch (eccezione SocketException) {
    
    } finalmente {
        if (serverSocket! = null && serverSocket.IsBound) {
            serverSocket.BeginAccept (null, 0, OnAccept, null);
        }
    }
    }
  3. Dopo aver stabilito la connessione, devi fare la stretta di mano . In base alla specifica 1.3 Apertura di handshake , dopo aver stabilito la connessione riceverai una richiesta HTTP di base con alcune informazioni. Esempio:

    OTTIENI / chatta HTTP / 1.1
    Host: server.example.com
    Aggiornamento: websocket
    Connessione: aggiornamento
    Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ ==
    Origine: http://example.com
    Sec-WebSocket-Protocol: chat, superchat
    Versione Sec-WebSocket: 13

    Questo esempio si basa sulla versione del protocollo 13. Tieni presente che le versioni precedenti presentano alcune differenze, ma la maggior parte delle ultime sono compatibili tra loro. Browser diversi potrebbero inviarti alcuni dati aggiuntivi. Ad esempio i dettagli del browser e del sistema operativo, cache e altri.

    In base ai dettagli di handshake forniti, è necessario generare righe di risposta, sono per lo più le stesse, ma conterranno Accpet-Key, che si basa sulla Sec-WebSocket-Key fornita. Nella specifica 1.3 è descritto chiaramente come generare la chiave di risposta. Ecco la mia funzione che ho usato per V13:

    stringa privata statica guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
    stringa privata AcceptKey (chiave stringa di riferimento) {
        stringa longKey = chiave + guid;
        SHA1 sha1 = SHA1CryptoServiceProvider.Create ();
        byte [] hashBytes = sha1.ComputeHash (System.Text.Encoding.ASCII.GetBytes (longKey));
        return Convert.ToBase64String (hashBytes);
    }
    

    La risposta della stretta di mano ha questo aspetto:

    HTTP / 1.1 101 commutazione dei protocolli
    Aggiornamento: websocket
    Connessione: aggiornamento
    Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK + xOo =

    Ma la chiave di accettazione deve essere quella generata in base alla chiave fornita dal client e al metodo AcceptKey fornito in precedenza. Inoltre, assicurati di inserire due nuove righe "\ r \ n \ r \ n" dopo l'ultimo carattere del tasto di accettazione.

  4. Dopo che la risposta dell'handshake è stata inviata dal server, il client dovrebbe attivare la funzione " onopen ", il che significa che puoi inviare messaggi dopo.
  5. I messaggi non vengono inviati in formato raw, ma hanno frame di dati . Inoltre, dal client al server implementa il mascheramento per i dati in base ai 4 byte forniti nell'intestazione del messaggio. Sebbene da server a client non sia necessario applicare il mascheramento ai dati. Leggere la sezione 5. Framing dei dati nelle specifiche. Ecco copia-incolla dalla mia implementazione. Non è codice pronto per l'uso e deve essere modificato, lo sto postando solo per dare un'idea e una logica generale di lettura / scrittura con il framing WebSocket. Vai a questo collegamento .
  6. Dopo aver implementato il framing, assicurati di ricevere i dati nel modo corretto utilizzando i socket. Ad esempio, per evitare che alcuni messaggi vengano uniti in uno solo, poiché il protocollo TCP è ancora un protocollo basato sul flusso. Ciò significa che devi leggere SOLO una quantità specifica di byte. La lunghezza del messaggio è sempre basata sull'intestazione e fornisce i dettagli sulla lunghezza dei dati nell'intestazione stessa. Quindi, quando ricevi i dati da Socket, ricevi prima 2 byte, ottieni i dettagli dall'intestazione in base alla specifica Framing, quindi se la maschera ha fornito altri 4 byte, quindi la lunghezza potrebbe essere 1, 4 o 8 byte in base alla lunghezza dei dati. E dopo i dati stessi. Dopo averlo letto, applica lo smascheramento e i dati del messaggio sono pronti per l'uso.
  7. Potresti voler utilizzare un protocollo dati , ti consiglio di utilizzare JSON a causa dell'economia del traffico e facile da usare sul lato client in JavaScript. Per il lato server potresti voler controllare alcuni parser. Ce ne sono molti, google può essere davvero utile.

L'implementazione del proprio protocollo WebSocket ha sicuramente alcuni vantaggi e una grande esperienza che si ottiene, oltre al controllo sul protocollo stesso. Ma devi dedicare un po 'di tempo a farlo e assicurarti che l'implementazione sia altamente affidabile.

Allo stesso tempo potresti dare un'occhiata a soluzioni pronte per l'uso che Google (di nuovo) ha abbastanza.


Immagino di essere bloccato sulla stretta di mano. quando si riceve una nuova connessione devo inviare al client l'hash sha1 della chiave lunga più la chiave corta giusto?
Tono Nam

Ho aggiunto maggiori informazioni nella sezione 3. Descrive maggiori dettagli sull'handshake dal lato server.
moka

1
Inoltre, assicurati che se nella richiesta vengono forniti i protocolli, utilizzali in risposta per la linea Sec-WebSocket-Protocol. Ma solo se è previsto a richiesta. Inoltre non è necessaria la versione per la risposta. E aggiungi un'altra NewLine alla fine. Inoltre invia l'intera stringa di risposta codificata utilizzando UTF8: Encoding.UTF8.GetBytes (responseBytes)
moka

Siamo chiusi. Grazie mille per l'aiuto. Sono in grado di inviare un messaggio ora, ma credo che il messaggio sia crittografato. Dai un'occhiata alla mia modifica su cui inizierò a lavorare presto ...
Tono Nam

Devi implementare il data framing, credo che questo sarà il bit più complicato nell'implementazione del protocollo WebSocket. Aggiungerò il codice copia-incolla dalla mia implementazione nel post, ma assicurati di modificarlo, perché ha alcune cose da cambiare, ma nel complesso dà un'idea e una logica di lavoro con frame.
moka

10

(Risposta pubblicata a nome del PO) .

Adesso posso inviare dati. Questa è la mia nuova versione del programma grazie alle vostre risposte e al codice di @Maksims Mihejevs.

server

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>

Quando eseguo quel codice sono in grado di inviare e ricevere dati sia dal client che dal server. L'unico problema è che i messaggi vengono crittografati quando arrivano al server. Ecco i passaggi di come viene eseguito il programma:

inserisci qui la descrizione dell'immagine

Nota come viene crittografato il messaggio del client.


5

I WebSocket sono implementati con un protocollo che prevede l' handshake tra client e server . Non immagino che funzionino molto come le normali prese. Leggi il protocollo e chiedi alla tua applicazione di parlarne. In alternativa, utilizza una libreria WebSocket esistente o .Net4.5beta che ha un'API WebSocket .


Ovviamente funzionano in modo molto simile alle normali prese. Il socket è a un livello inferiore rispetto al protocollo dell'applicazione e, come tale, non dipende da esso. Ciò significa che puoi eseguire FTP, SMTP, HTTP, WebSocket, ecc ... su un socket. Spetta all'implementatore assicurarsi che segua il protocollo correttamente o nessuno sarà in grado di parlare con il server.
SRM

5

Non sono riuscito a trovare un semplice esempio funzionante da nessuna parte (a partire dal 19 gennaio), quindi ecco una versione aggiornata. Ho la versione Chrome 71.0.3578.98.

Server Websocket C #:

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;
    }
}
}

HTML client e 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

Problema

Dato che stai usando WebSocket, spender è corretto. Dopo aver ricevuto i dati iniziali da WebSocket, è necessario inviare il messaggio di handshake dal server C # prima che possano fluire ulteriori informazioni.

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

Qualcosa del genere.

Puoi fare qualche ricerca in più su come funziona WebSocket su w3 o google.

Collegamenti e risorse

Ecco una specifica del protocollo: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76#section-1.3

Elenco di esempi di lavoro:


Inoltre sto usando la codifica UTF8. Dovrei usarne uno diverso come ASCII?
Tono Nam

@TonoNam: Per quanto ne so, la codifica UTF8 è corretta, anche se non sono un esperto di HTML5, quindi non lo so per certo.
caesay

L'ho fatto funzionare con Safari !!! Ne ho bisogno per farlo funzionare con Google Chrome. Tutti gli esempi si connettono ma nessuno invia i dati correttamente. Continuerò a provare. Grazie mille per l'aiuto!
Tono Nam

Naturalmente ... Se ancora non riesco a farlo funzionare, trasformerò questa domanda in una generosità! Sono davvero curioso di vedere questo funzionamento. Grazie per l'aiuto
Tono Nam

Il collegamento alle specifiche del protocollo non è aggiornato. Safari lo utilizza ancora, ma altri browser sono passati all'RFC 6455 incompatibile . Inoltre, mentre hai ragione sul fatto che la connessione iniziale richiede un po 'di negoziazione, altri messaggi no.
simonc
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.