【问题标题】:TcpListener write to ClientWebSocketTcpListener 写入 ClientWebSocket
【发布时间】:2021-07-09 17:15:53
【问题描述】:

我目前正在创建一个将在浏览器中运行并连接了 c# 服务器的项目。

服务器使用 TcpListener 接受连接和接收消息,但我希望服务器能够响应客户端。这给我带来了一些问题。

这是我的客户的代码:

        private ClientWebSocket socket;

        internal async Task InitAsync(string host, int port, GamePacketParser parser)
        {
            Logger.Info("Setting up the socket connection...");

            socket = new ClientWebSocket();
            await socket.ConnectAsync(new Uri($"ws://{host}:{port}/"), CancellationToken.None);

            Logger.Info("Successfully established the connection.");
            this.parser = parser;
            buffer = new byte[GameSocketManagerStatics.BUFFER_SIZE];

            Task.Run(recieve);
        }

        private async Task recieve()
        {
            Logger.Debug("Starting Reciever.....");
            var result = await socket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);

            var packet = new byte[result.Count];
            Array.Copy(buffer, packet, result.Count);

            ///parser.handlePacketData(packet);

            Logger.Debug($"Recieved: {Encoding.UTF8.GetString(packet)}");
            ///Task.Run(recieve); //Start receiving again
        }

        public async Task SendData(byte[] data)
        {
            Logger.Debug("Triggerd send");
            string packet = BitConverter.ToString(data);
            await socket.SendAsync(new ArraySegment<byte>(data), WebSocketMessageType.Text, true, CancellationToken.None);
            Logger.Info($"Sended Data: {packet}");
        }


上面的代码只是通过网络套接字连接到服务器。发送数据包工作正常。服务器发回数据的第二次,客户端将不再向服务器发送任何数据。就像它卡住了一样。

        static void Main(string[] args)
        {
            string ip = "127.0.0.1";
            int port = 30000;
            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();
            Console.WriteLine("A client connected.");

            NetworkStream stream = client.GetStream();

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

            byte[] message = Encoding.UTF8.GetBytes("Connection is established");
            stream.Write(message, 0, message.Length);

         }

问题可能是因为它没有为WebSockets编码,但是我尝试了很多在线的编码解决方案(例如:How can I send and receive WebSocket messages on the server side?)但是即使使用那些编码器,它似乎也没有解决问题。

提前感谢您的帮助。我对 WebSockets 还很陌生,所以允许用勺子喂食。

【问题讨论】:

  • 服务器不应该从套接字读取吗?
  • 读取对于服务器来说工作得很好。阅读在客户端上不起作用。当服务器写入客户端时,客户端 ReceiveAsync() 将阻塞 SendAsync(),因为它已经收到了一些数据,但没有成功读取数据。

标签: c# websocket tcplistener


【解决方案1】:

aepot 你的回答很好,但我真的希望我的服务器在 TCP 级别,如果我想在使用套接字的官方服务器上使用它,我需要更改很多代码。

我一直在深入研究WebSockets,经过一番搜索我发现,我基本上需要在发送数据之前发送一个标头。我不知道如何创建该标题,但我在网上找到了一些代码。 (我已经搜索了大约 12 个小时:?)

解决办法:

        protected int GetHeader(bool finalFrame, bool contFrame)
        {
            int header = finalFrame ? 1 : 0;//fin: 0 = more frames, 1 = final frame
            header = (header << 1) + 0;//rsv1
            header = (header << 1) + 0;//rsv2
            header = (header << 1) + 0;//rsv3
            header = (header << 4) + (contFrame ? 0 : 1);//opcode : 0 = continuation frame, 1 = text
            header = (header << 1) + 0;//mask: server -> client = no mask

            return header;
        }


        protected byte[] IntToByteArray(ushort value)
        {
            var ary = BitConverter.GetBytes(value);
            if (BitConverter.IsLittleEndian)
            {
                Array.Reverse(ary);
            }

            return ary;
        }

        public static IEnumerable<string> SplitInGroups(this string original, int size)
        {
            var p = 0;
            var l = original.Length;
            while (l - p > size)
            {
                yield return original.Substring(p, size);
                p += size;
            }
            yield return original.Substring(p);
        }
public static void SendMessage(string packet) {
   Queue<string> que = new Queue<string>(packet.SplitInGroups(125)); //Make it so the message is never longer then 125 (Split the message into parts & store them in a queue)
   int len = que.Count;

   while (que.Count > 0)
   {
      var header = GetHeader(
         que.Count > 1 ? false : true,
         que.Count == len ? false : true
      ); //Get the header for a part of the queue

      byte[] list = Encoding.UTF8.GetBytes(qui.Dequeue()); //Get part of the message out of the queue
      header = (header << 7) + list.Length; //Add the length of the part we are going to send

      //Send the header & message to client
      stream.write(IntToByteArray((ushort)header));
      stream.write(list);
   }
}

我自己并没有编写此代码,但遗憾的是,我无法找到我从中获取它的链接,以感谢编写代码的人。

【讨论】:

    猜你喜欢
    • 2012-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多