Publicidad


Tema resuelto
Este tema está marcado como resuelto y, como tal, no requiere atención a menos que desee solucionar este problema.

Multi cliente en servidor - WebSocket C#

Publicado por detectivejd, 22 Diciembre de 2022, 16:31

Tema anterior - Siguiente tema

0 Usuarios y 1 Visitante están viendo este tema.

detectivejd

Hola a todos, espero que estén bien, necesito ayuda urgente: Me pidieron que investigue sobre WebSocket y se necesita que el servidor pueda recibir más de un cliente, pero no sé cómo adaptar el uso de hilos a mi código al cuál colocaré:

Servidor
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;

namespace Consola
{
    internal class Program
    {
        static List<TcpClient> tcpClients = new List<TcpClient>();
        static void Main(string[] args)
        {
            string ip = "127.0.0.1";
            int port = 8080;
            var server = new TcpListener(IPAddress.Parse(ip), port);

            server.Start();
            Console.WriteLine("Server has started on {0}:{1}, Waiting for a connection...", ip, port);

            TcpClient client = server.AcceptTcpClient();
            tcpClients.Add(client);
           
            Console.WriteLine("A client connected.");

            NetworkStream stream = client.GetStream();

            // enter to an infinite cycle to be able to handle every change in stream
            while (true)
            {
                while (!stream.DataAvailable) ;
                while (client.Available < 3) ; // match against "get"

                byte[] bytes = new byte[client.Available];
                stream.Read(bytes, 0, client.Available);
                string s = Encoding.UTF8.GetString(bytes);

                if (Regex.IsMatch(s, "^GET", RegexOptions.IgnoreCase))
                {
                    Console.WriteLine("=====Handshaking from client=====\n{0}", s);

                    // 1. Obtain the value of the "Sec-WebSocket-Key" request header without any leading or trailing whitespace
                    // 2. Concatenate it with "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" (a special GUID specified by RFC 6455)
                    // 3. Compute SHA-1 and Base64 hash of the new value
                    // 4. Write the hash back as the value of "Sec-WebSocket-Accept" response header in an HTTP response
                    string swk = Regex.Match(s, "Sec-WebSocket-Key: (.*)").Groups[1].Value.Trim();
                    string swka = swk + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
                    byte[] swkaSha1 = System.Security.Cryptography.SHA1.Create().ComputeHash(Encoding.UTF8.GetBytes(swka));
                    string swkaSha1Base64 = Convert.ToBase64String(swkaSha1);

                    // HTTP/1.1 defines the sequence CR LF as the end-of-line marker
                    byte[] response = Encoding.UTF8.GetBytes(
                        "HTTP/1.1 101 Switching Protocols\r\n" +
                        "Connection: Upgrade\r\n" +
                        "Upgrade: websocket\r\n" +
                        "Sec-WebSocket-Accept: " + swkaSha1Base64 + "\r\n\r\n");

                    stream.Write(response, 0, response.Length);
                }
                else
                {
                    bool fin = (bytes[0] & 0b10000000) != 0,
                        mask = (bytes[1] & 0b10000000) != 0; // must be true, "All messages from the client to the server have this bit set"
                    int opcode = bytes[0] & 0b00001111, // expecting 1 - text message
                        offset = 2;
                    ulong msglen = (ulong)(bytes[1] & 0b01111111);

                    if (msglen == 126)
                    {
                        // bytes are reversed because websocket will print them in Big-Endian, whereas
                        // BitConverter will want them arranged in little-endian on windows
                        msglen = BitConverter.ToUInt16(new byte[] { bytes[3], bytes[2] }, 0);
                        offset = 4;
                    }
                    else if (msglen == 127)
                    {
                        // To test the below code, we need to manually buffer larger messages — since the NIC's autobuffering
                        // may be too latency-friendly for this code to run (that is, we may have only some of the bytes in this
                        // websocket frame available through client.Available).
                        msglen = BitConverter.ToUInt64(new byte[] { bytes[9], bytes[8], bytes[7], bytes[6], bytes[5], bytes[4], bytes[3], bytes[2] }, 0);
                        offset = 10;
                    }

                    if (msglen == 0)
                    {
                        Console.WriteLine("msglen == 0");
                    }
                    else if (mask)
                    {
                        byte[] decoded = new byte[msglen];
                        byte[] masks = new byte[4] { bytes[offset], bytes[offset + 1], bytes[offset + 2], bytes[offset + 3] };
                        offset += 4;

                        for (ulong i = 0; i < msglen; ++i)
                            decoded[i] = (byte)(bytes[(ulong)offset + i] ^ masks[i % 4]);

                        string text = Encoding.UTF8.GetString(decoded);
                        Console.WriteLine("{0}", text);
                    }
                    else
                        Console.WriteLine("mask bit not set");

                    Console.WriteLine();
                }
            }
        }
    }
}

Cliente
<!DOCTYPE html>
<html lang="en">
<head>
    <link href="Content/bootstrap.min.css" type="text/css" rel="stylesheet" />    
    <script src="Scripts/jquery-3.6.1.min.js" type="text/javascript"></script>    
</head>

<body>
    <div class="card">
        <div class="card-header">
            <h2>Prueba multi cliente con WebSocket</h2>
        </div>
        <div class="card-body">
            <p>
                <textarea cols="60" rows="6" id="cajadetexto"></textarea>
            </p>
            <p>
                <button id="boton" class="btn btn-primary">Enviar</button>
            </p>
            <p>
                <div id="salida"></div>
            </p>
        </div>
    </div>

    <style type="text/css">
        textarea {
            vertical-align: bottom;
        }

        #salida {
            overflow: auto;
        }

        #salida > p {
            overflow-wrap: break-word;
        }

        #salida span {
            color: blue;
        }

        #salida span.error {
            color: red;
        }
    </style>

    <script type="text/javascript">
        $(document).ready(function () {
            const wsUri = "ws://127.0.0.1:8080/";
            const websocket = new WebSocket(wsUri);

            $(document).on("click", "#boton", onClickButton);

            websocket.onopen = (e) => {
                writeToScreen("CONNECTED");
                doSend("WebSocket rocks");
            };

            websocket.onclose = (e) => {
                writeToScreen("DISCONNECTED");
            };

            websocket.onmessage = (e) => {
                writeToScreen(`<span>RESPONSE: ${e.data}</span>`);
            };

            websocket.onerror = (e) => {
                writeToScreen(`<span class="error">ERROR:</span> ${e.data}`);
            };

            function doSend(message) {
                writeToScreen(`SENT: ${message}`);
                websocket.send(message);
            }

            function writeToScreen(message) {
                $("#salida").append("<p>" + message + "</p>");
            }

            function onClickButton() {
                var text = $("#cajadetexto").val();

                text && doSend(text);
                $("#cajadetexto").val("");
                $("#cajadetexto").focus();
            }
        });
    </script>
</body>
</html>

Necesito que el cliente se ejecuta en un proyecto web mientras que el servidor en un proyecto de consola.
Intenté de todo, pero lo que obtuve lo que aparece en la imagen

Espero sus respuestas y saludos.

Rock Lee

No tendrias que tener problemas pero viendo la imagen muestra un error al momento de enviar no detecta correctamente el comando. No suelo poner todo junto pero ¿de donde sacaste el código? ahora estoy desde mi celular pero es claro entra en loop no tiene controles o formas de pararlo... Yo tengo separado el codigo para hacerlo funcionar en paralelo con una condicional cuando es por websocket te dejo el ejemplo para te des una idea:

static void Main(string[] args)
{
    try
    {
        WebSocketServer.Start("http://localhost:8080/");
        Console.WriteLine("Press any key to exit...\n");

        DateTimeOffset nextMessage = DateTimeOffset.Now.AddSeconds(BROADCAST_INTERVAL_SEC);
        while(!Console.KeyAvailable)
        {
            if(DateTimeOffset.Now > nextMessage)
            {
                nextMessage = DateTimeOffset.Now.AddSeconds(BROADCAST_INTERVAL_SEC);
                WebSocketServer.Broadcast($"Server time: {DateTimeOffset.Now.ToString("o")}");
            }
        }

        WebSocketServer.Stop();
    }
    catch (OperationCanceledException)
    {
        // normal upon task/token cancellation, disregard
    }
    Console.WriteLine("Program ending. Press any key...");
    Console.ReadKey(true);
}

Esto es encapsularlo para utilizarlo a tu gusto pero no se si es un trabajo/prueba debes hacer limitando como hacerlo sino podes hacerlo por API interno para procesrlo y devuelva los valores ahorrando mucho... si explicas mas seria genial!


Saludos Familia!

detectivejd

#2
Hola, pude implementar que el servidor pueda tener varios clientes mediante el uso de hilos:

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;

namespace Consola
{
    public class Program
    {
        private static TcpListener tcpListener = new TcpListener(
            IPAddress.Parse("127.0.0.1"), 
            8080
        );
        public static void Main(string[] args)
        {
            tcpListener.Start();
            while(true)
            {
                Thread nuevoHilo = new Thread(new ThreadStart(Listeners));
                nuevoHilo.Start();
            }
        }

        private static void Listeners()
        {
            Socket client = tcpListener.AcceptSocket();
            if (client.Connected)
            {
                Console.WriteLine("Client:" + client.RemoteEndPoint + " now connected to server.");
                NetworkStream stream = new NetworkStream(client);

                while (true)
                {
                    while (!stream.DataAvailable) ;
                    while (client.Available < 3) ; // match against "get"

                    byte[] bytes = new byte[client.Available];
                    stream.Read(bytes, 0, client.Available);
                    string s = Encoding.UTF8.GetString(bytes);

                    if (Regex.IsMatch(s, "^GET", RegexOptions.IgnoreCase))
                    {
                        Console.WriteLine("=====Handshaking from client=====\n{0}", s);

                        // 1. Obtain the value of the "Sec-WebSocket-Key" request header without any leading or trailing whitespace
                        // 2. Concatenate it with "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" (a special GUID specified by RFC 6455)
                        // 3. Compute SHA-1 and Base64 hash of the new value
                        // 4. Write the hash back as the value of "Sec-WebSocket-Accept" response header in an HTTP response
                        string swk = Regex.Match(s, "Sec-WebSocket-Key: (.*)").Groups[1].Value.Trim();
                        string swka = swk + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
                        byte[] swkaSha1 = System.Security.Cryptography.SHA1.Create().ComputeHash(Encoding.UTF8.GetBytes(swka));
                        string swkaSha1Base64 = Convert.ToBase64String(swkaSha1);

                        // HTTP/1.1 defines the sequence CR LF as the end-of-line marker
                        byte[] response = Encoding.UTF8.GetBytes(
                            "HTTP/1.1 101 Switching Protocols\r\n" +
                            "Connection: Upgrade\r\n" +
                            "Upgrade: websocket\r\n" +
                            "Sec-WebSocket-Accept: " + swkaSha1Base64 + "\r\n\r\n");

                        stream.Write(response, 0, response.Length);
                    }
                    else
                    {
                        bool fin = (bytes
[o]& 0b10000000) != 0,
                            mask = (bytes[1] & 0b10000000) != 0; // must be true, "All messages from the client to the server have this bit set"
                        int opcode = bytes
[o]& 0b00001111, // expecting 1 - text message
                            offset = 2;
                        ulong msglen = (ulong)(bytes[1] & 0b01111111);

                        if (msglen == 126)
                        {
                            // bytes are reversed because websocket will print them in Big-Endian, whereas
                            // BitConverter will want them arranged in little-endian on windows
                            msglen = BitConverter.ToUInt16(new byte[] { bytes[3], bytes[2] }, 0);
                            offset = 4;
                        }
                        else if (msglen == 127)
                        {
                            // To test the below code, we need to manually buffer larger messages — since the NIC's autobuffering
                            // may be too latency-friendly for this code to run (that is, we may have only some of the bytes in this
                            // websocket frame available through client.Available).
                            msglen = BitConverter.ToUInt64(new byte[] { bytes[9], bytes[8], bytes[7], bytes[6], bytes[5], bytes[4], bytes[3], bytes[2] }, 0);
                            offset = 10;
                        }

                        if (msglen == 0)
                        {
                            Console.WriteLine("msglen == 0");
                        }
                        else if (mask)
                        {
                            byte[] decoded = new byte[msglen];
                            byte[] masks = new byte[4] { bytes[offset], bytes[offset + 1], bytes[offset + 2], bytes[offset + 3] };
                            offset += 4;

                            for (ulong i = 0; i < msglen; ++i)
                                decoded[i] = (byte)(bytes[(ulong)offset + i] ^ masks[i % 4]);

                            string text = Encoding.UTF8.GetString(decoded);
                            Console.WriteLine("{0}", text);
                        }
                        else
                            Console.WriteLine("mask bit not set");

                        Console.WriteLine();
                    }
                }
            }

            client.Close();
        }
    }
}

Ahora lo que necesito hacer son 2 cosas: hacer que el frontend del cliente notifique las mensajes ajenos al suyo, y cuando dejo muy quieto el proyecto da el error de OutOfMemoryException

Pongo la imagen del frontend para que veas a que me refiero

Rock Lee

Claro te va a tirar esos errores por no tener controles por ejemplo pasarlo en buffer antes de trabajarlo por ejemplo "byte[] buffer = new byte[4096];" limitamos y forzamos a refrescar cuando llega al limite... ahora estoy con tema preparativos de navidad por lo que no puedo verlo mas a profundidad pero puedo guiarte en esos detalles. Aparte recomendar hacer un const int con 120 segundos (tomando el tiempo servidor) ademas preguntar ¿viste este topic MDN Web Docs en github?

Aunque pensando un poco mas un socket es una conexión punto a punto, es decir un servidor, un cliente. Por lo cual para admitir un servidor con varios clientes, necesitas varios sockets (uno por cliente). La forma más fácil seria configurar cada cliente como un subproceso separado que crea un socket y lo prueba para escuchar. Cuando un cliente se conecta a él, crea un nuevo hilo con un nuevo socket para el siguiente, y así sucesivamente. Cuando el zócalo se desconecta, el subproceso también finaliza pero no se hasta que punto podes modificar el código central...


Saludos Familia!

detectivejd

Hola, ¿cómo estás? primero gracias por responder, respecto a la pregunta

Citar¿viste este topic MDN Web Docs en github?

Justamente es el código en el que probé los socket 1 a 1, cuando dices de subprocesos te refieres a funciones, siendo así la única que veo probable cambiar es Listeners para hacer lo que dices,

CitarPor lo cual para admitir un servidor con varios clientes, necesitas varios sockets (uno por cliente). La forma más fácil seria configurar cada cliente como un subproceso separado que crea un socket y lo prueba para escuchar. Cuando un cliente se conecta a él, crea un nuevo hilo con un nuevo socket para el siguiente, y así sucesivamente.

Por otro lado, solo por curiosidad, ¿crees que poner un largo al array de bytes sería la mejor opción?, mi pregunta es más por desconocimiento de los socket.

Citarbyte[] buffer = new byte[4096];

Creo que esto lo retomaré el lunes o el martes cuando vuelva a trabajar. Gracias.

Rock Lee

Cita de: detectivejd en 24 Diciembre de 2022, 01:05Justamente es el código en el que probé los socket 1 a 1, cuando dices de subprocesos te refieres a funciones, siendo así la única que veo probable cambiar es Listeners para hacer lo que dices

Claro al menos es la única manera lo veo sino armar archivos e ir importando pero no se si es correcto... tendría que probar pero ando algo oxidado con los sockets

Cita de: detectivejd en 24 Diciembre de 2022, 01:05Por otro lado, solo por curiosidad, ¿crees que poner un largo al array de bytes sería la mejor opción?, mi pregunta es más por desconocimiento de los socket.

Si es algo chico puede ser útil aunque no se recomendable pero si tiene ser algo escalable a gran tamaño en verdad no es recomendable. La mejor opción es limitar los bytes o poner limites razonable refrescando (usando buffer o cache puede ser una buena practica) por si necesitas una gran demanda. Igualmente algo tan puntual empezando puede ser bastante estresante porque esto es algo medio intermedio/avanzado dependiendo como necesitas complementarlo.


Saludos Familia!

detectivejd

#6
Pude solucionarlo, todo lo que tuve que hacer era que solo se generen nuevos hilos cuando hay clientes conectándose, hice una prueba de 30 minutos y el "OutOfMemoryException" no apareció para nada.

Todo lo que queda por hacer es que las vistas del frontend actualicen cuando cada uno escribe algo.

Coloco el código, porque si bien tengo implementado el código para el tema de respuestas de clientes, el mismo no notifica:

<!DOCTYPE html>
<html lang="en">
<head>
    <link href="Content/bootstrap.min.css" type="text/css" rel="stylesheet" />    
    <script src="Scripts/jquery-3.6.1.min.js" type="text/javascript"></script>    
</head>

<body>
    <div class="card">
        <div class="card-header">
            <h2>Prueba multi cliente con WebSocket</h2>
        </div>
        <div class="card-body">
            <p>
                <textarea cols="60" rows="6" id="cajadetexto"></textarea>
            </p>
            <p>
                <button id="boton" class="btn btn-primary">Enviar</button>
            </p>
            <p>
                <div id="salida"></div>
            </p>
        </div>
    </div>

    <style type="text/css">
        textarea {
            vertical-align: bottom;
        }

        #salida {
            overflow: auto;
        }

        #salida > p {
            overflow-wrap: break-word;
        }

        #salida span {
            color: blue;
        }

        #salida span.error {
            color: red;
        }
    </style>

    <script type="text/javascript">
        $(document).ready(function () {
            const wsUri = "ws://127.0.0.1:8080/";
            const websocket = new WebSocket(wsUri);

            $(document).on("click", "#boton", onClickButton);

            websocket.onopen = (e) => {
                writeToScreen("CONNECTED");
                doSend("WebSocket rocks");
            };

            websocket.onclose = (e) => {
                writeToScreen("DISCONNECTED");
            };

            websocket.onmessage = (e) => {
                writeToScreen(`<span>RESPONSE: ${e.data}</span>`);
            };

            websocket.onerror = (e) => {
                writeToScreen(`<span class="error">ERROR:</span> ${e.data}`);
            };

            function doSend(message) {
                writeToScreen(`SENT: ${message}`);
                websocket.send(message);
            }

            function writeToScreen(message) {
                $("#salida").append("<p>" + message + "</p>");
            }

            function onClickButton() {
                var text = $("#cajadetexto").val();

                text && doSend(text);
                $("#cajadetexto").val("");
                $("#cajadetexto").focus();
            }
        });
    </script>
</body>
</html>

En la imagen coloco a que me refiero con notificaciones.

Rock Lee

Eso es bueno pudieras encontrar la solucion y ademas dejar la posible respuesta, ahora con respecto a la "notificación" no me queda claro del todo sobre todo si lo haces por websocket o directo con PHP aunque no se si es buena idea actualizar de tal manera puede generar algun loop. Deberia probar si funciona como lo pienso pero seria agregar un paso mas y al final muestre el resultado sino es hacerlo medio en vivo...


Saludos Familia!

detectivejd

Todo lo hace el websocket, cuando los clientes (vista html) se conectan, el servidor (aplicación de consola en C#) detecta la existencia de ellos, cuando un cliente ingresa algo y lo envía, el servidor capta lo ingresado y el resto de los clientes ven lo que ingresó el antes mencionado.

La funcionalidad que involucra las "notificaciones" en las vistas, es ésta:

websocket.onmessage = (e) => {
   writeToScreen(`<span>RESPONSE: ${e.data}</span>`);
};

Rock Lee

En ese caso lo que podes hacer es ampliar el tema de la notificación osea encapsular el proceso mas ampliamente para muestre cada notificación aunque es algo molesto podes poner un limite de notificaciones activas para no entre en loop... aunque puede ser no estoy durmiendo bien no entiendo si es pregunta o respuesta, por favor podes explicar algo mas!


Saludos Familia!

detectivejd

#10
Resolví el problema, resulta que se necesitaba codificar los mensajes para que el servidor sea capaz de notificar a los otros clientes desde la vista html, por otro lado, necesitaba una lista de clientes para poder todos los clientes conectados y posteriormente ver el tema de notificaciones en tiempo real. Como dato curioso la vista html queda relegado del sistema excepto para interactuar con el servidor

Paso el código completo.

Servidor

using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Linq;

namespace Consola
{
    public class Program
    {
        private static List<Socket> clients = new List<Socket>();
        private static TcpListener tcpListener = new TcpListener(
            IPAddress.Parse("127.0.0.1"), 
            8080
        );
        public static void Main(string[] args)
        {
            tcpListener.Start();
            while(true)
            {
                Socket client = tcpListener.AcceptSocket();
                if (client.Connected)
                {
                    clients.Add(client);
                    Thread nuevoHilo = new Thread(() => Listeners(client));
                    nuevoHilo.Start();
                }                    
            }
        }

        private static void Listeners(Socket client)
        {
            Console.WriteLine("Client:" + client.RemoteEndPoint + " now connected to server.");
            NetworkStream stream = new NetworkStream(client);

            while (true)
            {
                while (!stream.DataAvailable) ;
                while (client.Available < 3) ; // match against "get"

                byte[] bytes = new byte[client.Available];
                stream.Read(bytes, 0, bytes.Length);
                string s = Encoding.UTF8.GetString(bytes);

                if (Regex.IsMatch(s, "^GET", RegexOptions.IgnoreCase))
                {
                    Console.WriteLine("=====Handshaking from client=====\n{0}", s);

                    // 1. Obtain the value of the "Sec-WebSocket-Key" request header without any leading or trailing whitespace
                    // 2. Concatenate it with "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" (a special GUID specified by RFC 6455)
                    // 3. Compute SHA-1 and Base64 hash of the new value
                    // 4. Write the hash back as the value of "Sec-WebSocket-Accept" response header in an HTTP response
                    string swk = Regex.Match(s, "Sec-WebSocket-Key: (.*)").Groups[1].Value.Trim();
                    string swka = swk + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
                    byte[] swkaSha1 = System.Security.Cryptography.SHA1.Create().ComputeHash(Encoding.UTF8.GetBytes(swka));
                    string swkaSha1Base64 = Convert.ToBase64String(swkaSha1);

                    // HTTP/1.1 defines the sequence CR LF as the end-of-line marker
                    byte[] response = Encoding.UTF8.GetBytes(
                        "HTTP/1.1 101 Switching Protocols\r\n" +
                        "Connection: Upgrade\r\n" +
                        "Upgrade: websocket\r\n" +
                        "Sec-WebSocket-Accept: " + swkaSha1Base64 + "\r\n\r\n");

                    stream.Write(response, 0, response.Length);
                }
                else
                {
                    var text = DecodeMessage(bytes);

                    Console.WriteLine("{0}", text);
                        
                    var otherClients = clients.Where(
                            c => c.RemoteEndPoint != client.RemoteEndPoint
                        ).ToList();

                    if (otherClients.Count > 0)
                    {
                        foreach (var cli in otherClients)
                        {
                            var sendMessage = EncodeMessageToSend(text);
                            cli.Send(sendMessage);
                        }
                    }

                    Console.WriteLine();
                }
            }
        }

        private static string DecodeMessage(byte[] bytes)
        {
            var secondByte = bytes[1];
            var dataLength = secondByte & 127;
            var indexFirstMask = 2;
            if (dataLength == 126)
                indexFirstMask = 4;
            else if (dataLength == 127)
                indexFirstMask = 10;

            var keys = bytes.Skip(indexFirstMask).Take(4);
            var indexFirstDataByte = indexFirstMask + 4;

            var decoded = new byte[bytes.Length - indexFirstDataByte];
            for (int i = indexFirstDataByte, j = 0; i < bytes.Length; i++, j++)
            {
                decoded[j] = (byte)(bytes[i] ^ keys.ElementAt(j % 4));
            }

            return Encoding.UTF8.GetString(decoded, 0, decoded.Length);
        }

        private static byte[] EncodeMessageToSend(string message)
        {
            byte[] response;
            byte[] bytesRaw = Encoding.UTF8.GetBytes(message);
            byte[] frame = new byte[10];

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

            frame[0] = (byte)129;
            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

<!DOCTYPE html>
<html lang="en">
<head>
    <link href="Content/bootstrap.min.css" type="text/css" rel="stylesheet" />
    <script src="Scripts/jquery-3.6.1.min.js" type="text/javascript"></script>
</head>

<body>
    <div class="card">
        <div class="card-header">
            <h2>Prueba multi cliente con WebSocket</h2>
        </div>
        <div class="card-body">
            <p>
                <textarea cols="60" rows="6" id="cajadetexto"></textarea>
            </p>
            <p>
                <button id="boton" class="btn btn-primary">Enviar</button>
            </p>
            <p>
                <div id="salida"></div>
            </p>
        </div>
    </div>

    <style type="text/css">
        textarea {
            vertical-align: bottom;
        }

        #salida {
            overflow: auto;
        }

        #salida > p {
            overflow-wrap: break-word;
        }

        #salida span {
            color: blue;
        }

        #salida span.error {
            color: red;
        }
    </style>

    <script type="text/javascript">
        $(document).ready(function () {
            const wsUri = "ws://127.0.0.1:8080/";
            const websocket = new WebSocket(wsUri);

            $(document).on("click", "#boton", onClickButton);

            websocket.onopen = (e) => {
                writeToScreen("CONNECTED");
            };

            websocket.onclose = (e) => {
                writeToScreen("DISCONNECTED");
            };

            websocket.onmessage = (e) => {
                writeToScreen("<span>RESPONSE: " + e.data + "</span>");
            };

            websocket.onerror = (e) => {
                writeToScreen(`<span class="error">ERROR:</span> ${e.data}`);
            };

            function doSend(message) {
                writeToScreen(`SENT: ${message}`);
                websocket.send(message);
            }

            function writeToScreen(message) {
                $("#salida").append("<p>" + message + "</p>");
            }

            function onClickButton() {
                var text = $("#cajadetexto").val();

                text && doSend(text);
                $("#cajadetexto").val("");
                $("#cajadetexto").focus();
            }
        });
    </script>
</body>
</html>

En la imagen adjunta queda demostrado como funciona. Muchas gracias por todo. Saludos.


Príncipe_Azul

Hola, interesante ese websocket en C#, me alegro que lo hayas podido solucionar, gracias por comentarnos cual fue la solución y también por dejar el código y la captura de pantalla del programa funcionando.


Saludos

Temas Similares (3)