Criação de um exemplo de WebSocket “Hello World”


86

Não entendo por que não consigo fazer o código a seguir funcionar. Quero me conectar com JavaScript ao meu aplicativo de console do servidor. Em seguida, envie os dados para o servidor.

Aqui está o código do servidor:

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

e aqui está o 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 executo esse código, acontece o seguinte:

Observe que, quando executo o JavaScript, o servidor aceita e estabelece uma conexão com êxito. No entanto, o JavaScript não é capaz de enviar dados. Sempre que coloco o método de envio, ele não envia, mesmo que uma conexão seja estabelecida. Como posso fazer isso funcionar?


10
Esta "pergunta" não parece mais ser uma pergunta e, portanto, não é realmente adequada ao formato do StackOverflow. FWIW, a mensagem do cliente não é criptografada, ela é mascarada (ofuscada) por XOR'ing contra um valor aleatório que é transmitido como parte do quadro. Este detalhe do protocolo existe para evitar ataques de envenenamento contra servidores proxy que podem interpretar mal o tráfego.
EricLaw

2
obrigado, esta resposta é muito útil :) ei, só uma coisa, é esta "string privada estática guid =" 258EAFA5-E914-47DA-95CA-C5AB0DC85B11 ";" coisa é sempre constante? se não, onde posso obter esses valores?
Charmie

2
Eu entendi: "Um servidor não deve mascarar nenhum quadro que ele envia ao cliente"
Charmie

6
Você provavelmente deveria ter deixado a pergunta original intacta. O objetivo das perguntas é apresentar o problema, não a solução. As respostas, como você poderia imaginar, são para as soluções.
Kehlan Krumme de

2
Por que o URL do WebSocket termina com '/ serviço' (ws: // localhost: 8080 / serviço)? Por que não apenas 'ws: // localhost: 8080'?
andree

Respostas:


72

WebSockets é um protocolo que depende de uma conexão de fluxo TCP. Embora WebSockets seja um protocolo baseado em mensagem.

Se você deseja implementar seu próprio protocolo, recomendo usar a especificação mais recente e estável (para 18/04/12) RFC 6455 . Esta especificação contém todas as informações necessárias sobre handshake e enquadramento. Bem como a maioria das descrições de cenários de comportamento tanto do lado do navegador quanto do lado do servidor. É altamente recomendável seguir as recomendações sobre o lado do servidor durante a implementação do seu código.

Em poucas palavras, eu descreveria como trabalhar com WebSockets assim:

  1. Crie o servidor Socket (System.Net.Sockets), ligue-o a uma porta específica e continue ouvindo com aceitação assíncrona de conexões. Algo parecido:

    Socket serverSocket = novo Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
    serverSocket.Bind (novo IPEndPoint (IPAddress.Any, 8080));
    serverSocket.Listen (128);
    serverSocket.BeginAccept (null, 0, OnAccept, null);
  2. Você deve aceitar a função "OnAccept" que implementará o handshake. No futuro, ele terá que estar em outro segmento se o sistema for projetado para lidar com uma grande quantidade de conexões por segundo.

    private void OnAccept (IAsyncResult result) {
    experimentar {
        Cliente de soquete = nulo;
        if (serverSocket! = null && serverSocket.IsBound) {
            cliente = serverSocket.EndAccept (resultado);
        }
        if (cliente! = nulo) {
            / * Handshaking e gerenciamento de ClientSocket * /
        }
    } catch (exceção SocketException) {
    
    } finalmente {
        if (serverSocket! = null && serverSocket.IsBound) {
            serverSocket.BeginAccept (null, 0, OnAccept, null);
        }
    }
    }
  3. Após o estabelecimento da conexão, é necessário realizar o handshake . Com base na especificação 1.3 Aperto de mão de abertura , após o estabelecimento da conexão, você receberá uma solicitação HTTP básica com algumas informações. Exemplo:

    GET / chat HTTP / 1.1
    Host: server.example.com
    Upgrade: websocket
    Conexão: Upgrade
    Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ ==
    Origem: http://example.com
    Protocolo Sec-WebSocket: chat, superchat
    Versão Sec-WebSocket: 13

    Este exemplo é baseado na versão do protocolo 13. Lembre-se de que as versões mais antigas têm algumas diferenças, mas a maioria das versões mais recentes são compatíveis. Navegadores diferentes podem enviar alguns dados adicionais. Por exemplo, detalhes do navegador e do sistema operacional, cache e outros.

    Com base nos detalhes de handshake fornecidos, você deve gerar linhas de resposta, elas são praticamente as mesmas, mas conterão Accpet-Key, que é baseada na Sec-WebSocket-Key fornecida. Na especificação 1.3, é descrito claramente como gerar a chave de resposta. Aqui está minha função que tenho usado para V13:

    string privada estática guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
    string privada AcceptKey (ref string key) {
        string longKey = chave + guid;
        SHA1 sha1 = SHA1CryptoServiceProvider.Create ();
        byte [] hashBytes = sha1.ComputeHash (System.Text.Encoding.ASCII.GetBytes (longKey));
        return Convert.ToBase64String (hashBytes);
    }
    

    A resposta do aperto de mão é assim:

    Protocolos de comutação HTTP / 1.1 101
    Upgrade: websocket
    Conexão: Upgrade
    Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK + xOo =

    Mas a chave de aceitação deve ser a gerada com base na chave fornecida pelo cliente e no método AcceptKey que forneci anteriormente. Além disso, certifique-se de colocar duas novas linhas após o último caractere da tecla de aceitação "\ r \ n \ r \ n".

  4. Depois que a resposta do handshake é enviada do servidor, o cliente deve acionar a função " onopen ", o que significa que você pode enviar mensagens depois.
  5. As mensagens não são enviadas em formato bruto, mas possuem Enquadramento de Dados . E do cliente ao servidor também implemente o mascaramento de dados com base nos 4 bytes fornecidos no cabeçalho da mensagem. Embora do servidor para o cliente você não precise aplicar mascaramento sobre os dados. Leia a seção 5. Enquadramento de dados nas especificações. Aqui está copiar e colar de minha própria implementação. Não é um código pronto para uso e precisa ser modificado, estou postando apenas para dar uma ideia e uma lógica geral de leitura / gravação com enquadramento WebSocket. Vá para este link .
  6. Após o enquadramento ser implementado, certifique-se de receber os dados da maneira correta usando os soquetes. Por exemplo, para evitar que algumas mensagens sejam mescladas em uma, porque o TCP ainda é um protocolo baseado em fluxo. Isso significa que você deve ler APENAS uma quantidade específica de bytes. O comprimento da mensagem é sempre baseado no cabeçalho e nos detalhes do comprimento dos dados fornecidos no próprio cabeçalho. Então, ao receber dados do Socket, primeiro receba 2 bytes, obtenha detalhes do cabeçalho com base na especificação de Framing, se a máscara forneceu outros 4 bytes e o comprimento pode ser 1, 4 ou 8 bytes com base no comprimento dos dados. E depois dos próprios dados. Depois de ler, aplique o desmascaramento e os dados da sua mensagem estarão prontos para uso.
  7. Você pode querer usar algum protocolo de dados , eu recomendo usar JSON devido à economia de tráfego e fácil de usar no lado do cliente em JavaScript. Para o lado do servidor, você pode querer verificar alguns dos analisadores. Há muitos deles, o Google pode ser muito útil.

Implementar o próprio protocolo WebSockets definitivamente traz alguns benefícios e ótima experiência, bem como o controle sobre o próprio protocolo. Mas você precisa gastar algum tempo fazendo isso e garantir que a implementação seja altamente confiável.

Ao mesmo tempo, você pode dar uma olhada em soluções prontas para usar que o Google (de novo) tem o suficiente.


Acho que estou preso no aperto de mão. quando uma nova conexão é recebida tenho que enviar para o cliente o sha1 hash da chave longa mais a chave curta certo?
Tono Nam

Eu adicionei mais informações na seção 3. Ela descreve mais detalhes sobre o handshake do lado do servidor.
moka de

1
Além disso, certifique-se de que, se forem fornecidos protocolos de solicitação, use os mesmos em resposta para a linha Sec-WebSocket-Protocol. Mas apenas se houver um pedido. Além disso, você não precisa da versão para resposta. E adicione outra NewLine ao final. Também enviar a string de resposta inteira codificada usando UTF8: Encoding.UTF8.GetBytes (responseBytes)
moka

Estamos perto. Muito obrigado pela ajuda. Consigo enviar uma mensagem agora, mas acredito que a mensagem está criptografada. Dê uma olhada na minha edição na qual começarei a trabalhar em breve ...
Tono Nam

Você tem que implementar o data framing, acredito que essa será a parte mais complicada da implementação do protocolo WebSockets. Vou adicionar o código copiar e colar da minha implementação na postagem, mas certifique-se de editá-lo, porque ele tem algumas coisas a mudar, mas no geral dá uma ideia e lógica de trabalhar com frame.
moka,

10

(Postado resposta em nome do OP) .

Posso enviar dados agora. Esta é a minha nova versão do programa graças às suas respostas e ao código de @Maksims Mihejevs.

Servidor

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 executo esse código, posso enviar e receber dados do cliente e do servidor. O único problema é que as mensagens são criptografadas quando chegam ao servidor. Aqui estão as etapas de como o programa é executado:

insira a descrição da imagem aqui

Observe como a mensagem do cliente é criptografada.


5

WebSockets são implementados com um protocolo que envolve handshake entre cliente e servidor . Não imagino que funcionem muito como soquetes normais. Leia o protocolo e faça seu aplicativo falar sobre ele. Como alternativa, use uma biblioteca WebSocket existente ou .Net4.5beta que possui uma API WebSocket .


É claro que eles funcionam de forma muito semelhante às tomadas normais. O soquete está em um nível inferior ao do protocolo do aplicativo e, como tal, não depende dele. Isso significa que você pode executar FTP, SMTP, HTTP, WebSockets, etc ... em um soquete. Cabe ao implementador certificar-se de que segue o protocolo corretamente ou ninguém conseguirá falar com o servidor.
SRM de

5

Não consegui encontrar um exemplo simples de trabalho em nenhum lugar (em 19 de janeiro), então aqui está uma versão atualizada. Tenho o Chrome versão 71.0.3578.98.

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

Cliente html 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

Questão

Já que você está usando WebSocket, o spender está correto. Depois de receber os dados iniciais do WebSocket, você precisa enviar a mensagem de handshake do servidor C # antes que qualquer outra informação possa fluir.

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

Algo nesse sentido.

Você pode fazer mais pesquisas sobre como o WebSocket funciona no w3 ou no google.

Links e recursos

Aqui está uma especificação do protocolo: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76#section-1.3

Lista de exemplos de trabalho:


Além disso, estou usando a codificação UTF8. Devo usar um diferente, como ASCII?
Tono Nam

@TonoNam: Pelo que eu sei, a codificação UTF8 está correta - embora eu não seja um especialista em HTML5, então não tenho certeza.
caesay

Eu fiz funcionar com o safari !!! Eu preciso fazer funcionar com o Google Chrome embora. Todos os exemplos se conectam, mas nenhum deles envia dados com sucesso. Vou continuar tentando. Muito obrigado pela ajuda!
Tono Nam

Claro ... Se eu ainda não conseguir fazer funcionar, vou fazer essa pergunta em uma recompensa! Estou muito curioso para ver isso funcionando. Obrigado pela ajuda
Tono Nam,

Seu link de especificações de protocolo está desatualizado. O Safari ainda usa isso, mas outros navegadores mudaram para o RFC 6455 incompatível . Além disso, embora você esteja certo de que a conexão inicial requer alguma negociação, outras mensagens não.
simonc
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.