11
votes

C # Server WebSocket HTML5

Je suis en train de créer un serveur C # Websocket mais je ne semble pas pour le faire fonctionner. J'ai maintenant un serveur qui accepte le TCPClient, reçoit la requête HTTP du client et qui essaie de renvoyer une réponse HTTP de sorte que le

Je crois que HTML5 poignée de main WebSocket peut être complété. Il y a quelque chose de mal avec ma poignée de main que le serveur envoie au client. J'ai lu le projet ( Websocket 76 projet ) que les États que, à la fin de la prise de contact d'une réponse doit être donnée aux deux touches qui sont donnés. Cette réponse se calcule par le serveur p>

Ceci est mon code:. P>

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!\n");

            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\r\n"
                    + "Upgrade: WebSocket\r\n" + "Connection: Upgrade\r\n"
                    + "Sec-WebSocket-Origin: http://localhost\r\n"
                    + "Sec-WebSocket-Location: ws://localhost:8181/websession\r\n"
                    + "\r\n";

                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 = "\r\n";
        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;
    }


0 commentaires

4 Réponses :


1
votes

Essayez d'envoyer les données de la poignée de main avant d'essayer de recevoir des données sur la prise

Voici un exemple qui pourrait vous aider

Webocksample


2 commentaires

Je n'essaie pas vraiment de recevoir des données avant la poignée de main, c'est la demande que le client envoie au serveur que j'écris sur l'écran de la console.


Une fois que vous obtenez une connexion que vous essayez de recevoir des données avant d'envoyer la réponse de la poignée de main "HTTP / 1.1 101 Websocket Protocol, etc." Je pense que vous devez envoyer ceci au moment où vous recevez une connexion. Avant de recevoir des données sur le flux qui est.



13
votes

Voici un exemple de serveur que j'ai écrit illustrer la phase de main de la poignée de main conformément au Draw-ietf-hybi-thewebsocketprotocol-00 : xxx

et un exemple de client: xxx


3 commentaires

Bonjour Darin, Tout d'abord +1 pour un échantillon de travail, j'adore ça. Cependant, j'ai essayé votre échantillon à l'aide du chrome 16, et il ne fonctionnait pas car Chrome, il n'envoie pas Sec-WebSockets-Key1 en-tête car votre serveur s'attend à ce que l'UA avez-vous utilisé pour ce test?


@ Eugeniomiró, j'ai utilisé chrome, aucune idée de la version qui était à l'époque où j'ai posté cette réponse: mai 2011. Ma réponse a été basée sur Draft-ietf-hybi-thewebsocketprotocol-00 . Il y a maintenant le RFC 6455 que je crois est la dernière spécification mais je n'ai aucune idée de laquelle une Le chrome 16 met-il en œuvre?


Bonjour Darin, j'ai trouvé Chrome maintenant, il envoie 13 une version sur les en-têtes, je suis donc suivi de là, merci pour votre réponse rapide!



1
votes

ne savez pas si vous pouvez compiler l'objectif c, mais Ce projet est vraiment assez cool . ..

Blackbox est un serveur HTTP de cacao incorporable - qui vous permet d'associer HTTP Ressources avec des objets de "répondeur" de cacao (genre de Web torsadé fait pour python) plutôt que des fichiers sur votre système de fichiers.

avec blackbox, vous pouvez créer des trembleurs de fichiers personnels en un enfer, écrire applications qui communiquent les unes avec les autres sur http, et facilement Créez des interfaces de contrôle Web pour des applications sans tête.

Il s'agit essentiellement d'un COMET Server dans un joli emballage. J'aimerais pouvoir en dire plus à ce sujet, mais je suis toujours en train de tenter de trouver des sockets moi-même ...

Veuillez noter que la fenêtre


0 commentaires

6
votes

Voici très simple WebSocket Echo Server que j'ai implémenté à l'aide de sockets simples.

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

namespace SimpleWebsocketServer {
    class Program {
        static void Main(string[] args) {
            var listeningSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            listeningSocket.Bind(new IPEndPoint(IPAddress.Any, port: 80));
            listeningSocket.Listen(0);

            while (true) {
                var clientSocket = listeningSocket.Accept();

                Console.WriteLine("A client connected.");

                var receivedData = new byte[1000000];
                var receivedDataLength = clientSocket.Receive(receivedData);

                var requestString = Encoding.UTF8.GetString(receivedData, 0, receivedDataLength);

                if (new Regex("^GET").IsMatch(requestString)) {
                    const string eol = "\r\n";

                    var receivedWebSocketKey = new Regex("Sec-WebSocket-Key: (.*)").Match(requestString).Groups[1].Value.Trim();
                    var keyHash = SHA1.Create().ComputeHash(Encoding.UTF8.GetBytes(receivedWebSocketKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"));

                    var response = "HTTP/1.1 101 Switching Protocols" + eol;
                    response += "Connection: Upgrade" + eol;
                    response += "Upgrade: websocket" + eol;
                    response += "Sec-WebSocket-Accept: " + Convert.ToBase64String(keyHash) + eol;
                    response += eol;

                    var responseBytes = Encoding.UTF8.GetBytes(response);

                    clientSocket.Send(responseBytes);
                }

                while (true) {
                    receivedData = new byte[1000000];
                    clientSocket.Receive(receivedData);

                    if ((receivedData[0] & (byte)Opcode.CloseConnection) == (byte)Opcode.CloseConnection) {
                        // Close connection request.
                        Console.WriteLine("Client disconnected.");
                        clientSocket.Close();
                        break;
                    } else {
                        var receivedPayload = ParsePayloadFromFrame(receivedData);
                        var receivedString = Encoding.UTF8.GetString(receivedPayload);

                        Console.WriteLine($"Client: {receivedString}");

                        var response = $"ECHO: {receivedString}";
                        var dataToSend = CreateFrameFromString(response);

                        Console.WriteLine($"Server: {response}");

                        clientSocket.Send(dataToSend);
                    }
                }
            }
        }

        public static byte[] ParsePayloadFromFrame(byte[] incomingFrameBytes) {
            var payloadLength = 0L;
            var totalLength = 0L;
            var keyStartIndex = 0L;

            // 125 or less.
            // When it's below 126, second byte is the payload length.
            if ((incomingFrameBytes[1] & 0x7F) < 126) {
                payloadLength = incomingFrameBytes[1] & 0x7F;
                keyStartIndex = 2;
                totalLength = payloadLength + 6;
            }

            // 126-65535.
            // When it's 126, the payload length is in the following two bytes
            if ((incomingFrameBytes[1] & 0x7F) == 126) {
                payloadLength = BitConverter.ToInt16(new[] { incomingFrameBytes[3], incomingFrameBytes[2] }, 0);
                keyStartIndex = 4;
                totalLength = payloadLength + 8;
            }

            // 65536 +
            // When it's 127, the payload length is in the following 8 bytes.
            if ((incomingFrameBytes[1] & 0x7F) == 127) {
                payloadLength = BitConverter.ToInt64(new[] { incomingFrameBytes[9], incomingFrameBytes[8], incomingFrameBytes[7], incomingFrameBytes[6], incomingFrameBytes[5], incomingFrameBytes[4], incomingFrameBytes[3], incomingFrameBytes[2] }, 0);
                keyStartIndex = 10;
                totalLength = payloadLength + 14;
            }

            if (totalLength > incomingFrameBytes.Length) {
                throw new Exception("The buffer length is smaller than the data length.");
            }

            var payloadStartIndex = keyStartIndex + 4;

            byte[] key = { incomingFrameBytes[keyStartIndex], incomingFrameBytes[keyStartIndex + 1], incomingFrameBytes[keyStartIndex + 2], incomingFrameBytes[keyStartIndex + 3] };

            var payload = new byte[payloadLength];
            Array.Copy(incomingFrameBytes, payloadStartIndex, payload, 0, payloadLength);
            for (int i = 0; i < payload.Length; i++) {
                payload[i] = (byte)(payload[i] ^ key[i % 4]);
            }

            return payload;
        }

        public enum Opcode {
            Fragment = 0,
            Text = 1,
            Binary = 2,
            CloseConnection = 8,
            Ping = 9,
            Pong = 10
        }

        public static byte[] CreateFrameFromString(string message, Opcode opcode = Opcode.Text) {
            var payload = Encoding.UTF8.GetBytes(message);

            byte[] frame;

            if (payload.Length < 126) {
                frame = new byte[1 /*op code*/ + 1 /*payload length*/ + payload.Length /*payload bytes*/];
                frame[1] = (byte)payload.Length;
                Array.Copy(payload, 0, frame, 2, payload.Length);
            } else if (payload.Length >= 126 && payload.Length <= 65535) {
                frame = new byte[1 /*op code*/ + 1 /*payload length option*/ + 2 /*payload length*/ + payload.Length /*payload bytes*/];
                frame[1] = 126;
                frame[2] = (byte)((payload.Length >> 8) & 255);
                frame[3] = (byte)(payload.Length & 255);
                Array.Copy(payload, 0, frame, 4, payload.Length);
            } else {
                frame = new byte[1 /*op code*/ + 1 /*payload length option*/ + 8 /*payload length*/ + payload.Length /*payload bytes*/];
                frame[1] = 127; // <-- Indicates that payload length is in following 8 bytes.
                frame[2] = (byte)((payload.Length >> 56) & 255);
                frame[3] = (byte)((payload.Length >> 48) & 255);
                frame[4] = (byte)((payload.Length >> 40) & 255);
                frame[5] = (byte)((payload.Length >> 32) & 255);
                frame[6] = (byte)((payload.Length >> 24) & 255);
                frame[7] = (byte)((payload.Length >> 16) & 255);
                frame[8] = (byte)((payload.Length >> 8) & 255);
                frame[9] = (byte)(payload.Length & 255);
                Array.Copy(payload, 0, frame, 10, payload.Length);
            }

            frame[0] = (byte)((byte)opcode | 0x80 /*FIN bit*/);

            return frame;
        }
    }
}


1 commentaires

J'ai passé plusieurs heures à la recherche d'un exemple de ligne de ligne de commande simple exemple sur DotNet sans gonfleur de la bibliothèque ni quelque chose de moins basique que de recevoir, d'envoyer et d'arrêter, ceci est le plus bas au point un.