Websocket will successfully establish a connection, but does not send messages correctly (C # Server)

After the fight, all morning I got a handshake, but now I'm actually stuck sending and receiving messages. I searched for answers to no avail, so I thought that I was finally activating here and asking: /

My client is still very simple:

function testWebSocket() { if (!window.WebSocket) { alert('WebSockets are NOT supported by your browser.'); return; } try { var ws = new WebSocket('ws://localhost:8181/websession'); ws.onopen = function () { alert('Handshake successfully established. Ready for data...'); }; ws.onmessage = function (e) { alert('Got WebSockets message: ' + e.data); } ws.onclose = function () { alert('Connection closed.'); }; } catch (e) { alert(e); } } 

yes, I made a lot of borrowing code for this ... I'm just trying to get a proof of concept working with a simple "chat application"

my server consists mainly of two classes: SocketServer.cs and SocketClient.cs

follow:

SocketServer.cs

 using System; using System.Collections.Generic; using System.Text; using System.Net.Sockets; using System.Net; using System.IO; namespace WebSocketServer.Entities { class SocketServer { public static Form1 parentForm; TcpListener socketServer; public static List<SocketClient> ClientList = new List<SocketClient>(); public SocketServer(Form1 pForm) { parentForm = pForm; parentForm.ApplyText("Socket Class Initiated\r\n"); socketServer = new TcpListener(IPAddress.Any, 8181); // tell the console that it started parentForm.ApplyText("Socket Server Started\r\n"); // create continuous loops to listen for new connections // start the listener socketServer.Start(); while (true) { // check for any incoming pending connections // create new socket client for new connection TcpClient socketConnection = socketServer.AcceptTcpClient(); DateTime now = DateTime.Now; //write message to console to indicate new connection parentForm.ApplyText("New Client Connected - " + now.ToString("MM/dd/yyyy h:mm:ss tt") + "\r\n"); // create new client object for this connection SocketClient socketClient = new SocketClient(socketConnection, parentForm); } } public static void CloseClient(SocketClient whichClient) { ClientList.Remove(whichClient); whichClient.Client.Close(); // dispose of the client object whichClient.Dispose(); whichClient = null; parentForm.ApplyText("Client Disconnected\r\n"); } public static void SendTextToClient(SocketClient sc, string text) { StreamWriter writer = new StreamWriter(sc.Client.GetStream()); // check if client is still connected, then send the text string try { if (sc.Client.Connected) { writer.WriteLine(text); writer.Flush(); writer = null; } } catch { CloseClient(sc); } } public static void SendBroadcast(string text) { StreamWriter writer; // loop through the array and send text to all clients foreach (SocketClient client in ClientList) { if (client.Client.Connected) { try { writer = new StreamWriter(client.Client.GetStream()); writer.WriteLine(text); writer.Flush(); writer = null; } catch { CloseClient(client); } } } } } } 

Socketclient.cs

 using System; using System.Collections.Generic; using System.Text; using System.Net.Sockets; using System.IO; using System.Threading; using System.Security.Cryptography; namespace WebSocketServer.Entities { class SocketClient { public TcpClient Client; StreamReader reader; StreamWriter writer; Form1 parentForm; public SocketClient(TcpClient client, Form1 pForm) { parentForm = pForm; Client = client; Thread clientThread = new Thread(new ThreadStart(StartClient)); clientThread.Start(); } private void StartClient() { SocketServer.ClientList.Add(this); // create a reader for this client reader = new StreamReader(Client.GetStream()); // create a writer for this client writer = new StreamWriter(Client.GetStream()); var headers = new Dictionary<string, string>(); string line = ""; while ((line = reader.ReadLine()) != string.Empty) { if (!string.IsNullOrEmpty(line)) { var tokens = line.Split(new char[] { ':' }, 2); if (!string.IsNullOrWhiteSpace(line) && tokens.Length > 1) { headers[tokens[0]] = tokens[1].Trim(); } } } String secWebSocketAccept = ComputeWebSocketHandshakeSecurityHash09(headers["Sec-WebSocket-Key"]); // send handshake to this client only writer.WriteLine("HTTP/1.1 101 Web Socket Protocol Handshake"); writer.WriteLine("Upgrade: WebSocket"); writer.WriteLine("Connection: Upgrade"); writer.WriteLine("WebSocket-Origin: http://localhost:63422/"); writer.WriteLine("WebSocket-Location: ws://localhost:8181/websession"); writer.WriteLine("Sec-WebSocket-Accept: " + secWebSocketAccept); writer.WriteLine(""); writer.Flush(); SocketServer.SendBroadcast("New Client Connected"); Thread clientRun = new Thread(new ThreadStart(RunClient)); clientRun.Start(); } public static String ComputeWebSocketHandshakeSecurityHash09(String secWebSocketKey) { const String MagicKEY = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; String secWebSocketAccept = String.Empty; // 1. Combine the request Sec-WebSocket-Key with magic key. String ret = secWebSocketKey + MagicKEY; // 2. Compute the SHA1 hash SHA1 sha = new SHA1CryptoServiceProvider(); byte[] sha1Hash = sha.ComputeHash(Encoding.UTF8.GetBytes(ret)); // 3. Base64 encode the hash secWebSocketAccept = Convert.ToBase64String(sha1Hash); return secWebSocketAccept; } private void RunClient() { try { string line = ""; while (true) { line = reader.ReadLine(); if (!string.IsNullOrEmpty(line)) { parentForm.ApplyText(line + "\r\n"); SocketServer.SendBroadcast(line); } } } catch { parentForm.ApplyText("Client Disconnected\r\n"); SocketServer.CloseClient(this); } } public void Dispose() { System.GC.SuppressFinalize(this); } } } 

I can connect to multiple instances in Chrome, and all connected clients are displayed on my server, and I see a warning that the handshake was successful. But when I try to send text from the client (the code is not shown above, but this is a pretty simple thing ws.send (text)), it gets to the server as garbled text. When I try to make writer.WriteLine ("whatever") from server to client, the onmessage event never fires. I did a lot of review after I finally got a handshake, sorted it out and did not find good examples of how to resolve this.

Should I not use StreamWriter? I missed something else in my handshake (maybe a protocol).

TIA for search and assistance.

Edit:

The code below works, but I don’t know how to change it to allow the length of the text in a dynamic format. I'm fine, just being able to send text that is 127 or less at the moment, but I can't figure out how to get even 4.

 public static void SendBroadcast(string text) { StreamWriter writer; // loop through the array and send text to all clients foreach (SocketClient client in ClientList) { if (client.Client.Connected) { try { NetworkStream l_Stream = client.Client.GetStream(); List<byte> lb = new List<byte>(); lb.Add(0x81); lb.Add(0x04); lb.AddRange(Encoding.UTF8.GetBytes("test")); l_Stream.Write(lb.ToArray(), 0, 6); } catch { CloseClient(client); } } } } 

I tried changing lb.Add (0x04) to lb.Add (0x07) and send "testing" without cubes. I am also confused by the fact that the parameters are l_Stream.Write (). I know this is an array of bytes, offset and size, but the size of what?

+4
source share
2 answers

Messages are not sent as plain text in recent versions of the specification. For more information, see the section on data cropping .

This wiki post is also very useful.

I also wrote a C ++ server ; the WsProtocol80 class shows how to read / write data.

EDIT: in your sample send code, byte 0x04 indicates a 4-byte message. This way you can set different values ​​and send messages up to 125 bytes. When you change the length of the message, you also need to update the last parameter to l_Stream.Write (which determines the number of bytes to write). Changing it to lb.Count will look better in all cases.

If you still find bitwise operations confusing and then want to send longer messages or read messages from the client, the link above to the wiki page includes a pseudo code that should be useful.

+4
source

I had the same problem, I found a solution:

  lb = new List<byte>(); lb.Add(0x81); size = message.Length;//get the message size lb.Add((byte)size); //get the size in bytes lb.AddRange(Encoding.UTF8.GetBytes(message)); stream.Write(lb.ToArray(), 0, size+2); //I do size+2 because we have 2 bytes plus 0x81 and (byte)size 

With this solution, you can send a larger message, but only <127 characters

Note: sorry, but my English is not very good. ^^

+2
source

Source: https://habr.com/ru/post/1394066/


All Articles