【问题标题】:websocket successfully handshaking, but not sending receiving messages correctly (C# Server)websocket成功握手,但没有正确发送接收消息(C#服务器)
【发布时间】:2012-02-23 14:56:05
【问题描述】:

在整个上午的战斗之后,我得到了握手工作,但现在我被困在实际发送和接收消息中。我一直在寻找无济于事的答案,所以我想我终于站出来问了:/

到目前为止,我的客户非常简单:

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

是的,我为此做了很多代码借用...我只是想通过一个简单的“聊天应用程序”获得概念验证

我的服务器主要由两个类组成,SocketServer.cs 和 SocketClient.cs

他们跟随:

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

}

我可以在 Chrome 中连接多个实例,并且我的服务器显示所有正在连接的客户端,并且我看到了握手成功的警报。但是当我尝试从客户端发送文本时(上面没有显示代码,但这是一个非常简单的 ws.send(text) 有点像),它会以乱码文本的形式到达服务器。当我尝试从服务器到客户端执行 writer.WriteLine("whatever") 时,onmessage 事件永远不会触发。在我终于解决握手问题后,我环顾四周,找不到任何解决此问题的好例子。

我不应该使用 StreamWriter 吗?我在握手中是否遗漏了其他内容(可能是协议)。

TIA 寻求帮助。

编辑:

以下代码有效,但我不知道如何修改它以允许动态大小的文本长度。我现在可以发送 127 或更少的文本,但我似乎无法掌握如何超过 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);
            }
        }
    }
}

我尝试将 lb.Add(0x04) 修改为 lb.Add(0x07) 并发送“测试”无骰子。我也对 l_Stream.Write() 参数是什么感到困惑。我知道这是字节数组、偏移量和大小,但大小是什么?

【问题讨论】:

    标签: c# .net html google-chrome websocket


    【解决方案1】:

    我遇到了同样的问题,我找到了解决方案:

                lb = new List<byte>();
                lb.Add(0x81);
                size = message.Length;//get the message's 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
    

    使用此解决方案,您可以发送更大的消息,但只能发送

    注意:对不起,我的英语不太好。 ^^

    【讨论】:

      【解决方案2】:

      在最新版本的规范中,消息不会以纯文本形式发送。详情请见data framing section

      这个wiki post也很有帮助。

      我还写了C++ server; WsProtocol80 类展示了如何读取/写入数据。

      编辑:在您的示例发送代码中,0x04 字节指定一个 4 字节消息。您可以通过这种方式设置不同的值并发送最多 125 个字节的消息。当您更改消息长度时,您还必须将最后一个参数更新为 l_Stream.Write(它指定要写入的字节数)。在所有情况下将其更改为 lb.Count 似乎会更好。

      如果您仍然觉得按位运算令人困惑,并且以后想要发送更长的消息或从客户端读取消息,那么上面指向 wiki 帖子的链接包含应该会有所帮助的伪代码。

      【讨论】:

      • 哇,这对我来说太希腊化了。我最终能够通过从 StreamWriter 切换到 NetworkStream 并从我找到的样本中写出一个字节数组来向客户端发送“测试”,但它将发送的文本限制为仅 4 个字符(我假设其中一个我添加到数组中的字节值导致了这种限制,但我对字节等了解不多)。感谢您的 C++ 示例,但我之前从未看过任何 C++ 内容,所以它不是很有帮助。我希望能够使用 StreamWriter 而不是 NetworkStream,并且我正在努力对自己进行更好的字节教育,但很挣扎。
      • 我更新了我的 OP,对我正在努力将“测试”发送给客户的内容进行了编辑。您是否有机会就我在该编辑中提出的问题提供一些见解?
      • 谢谢,这是一个很大的帮助。我还有另一个关于生成要添加到我的字节数组的十六进制值的问题,但这超出了这个问题的范围。
      猜你喜欢
      • 2013-12-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-30
      • 2013-11-12
      • 2017-09-02
      • 2021-02-28
      • 1970-01-01
      相关资源
      最近更新 更多