RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 854206
Accepted
Трипольский Пётр
Трипольский Пётр
Asked:2020-07-13 20:30:27 +0000 UTC2020-07-13 20:30:27 +0000 UTC 2020-07-13 20:30:27 +0000 UTC

在 C# 中实现 WebSocket 协议

  • 772

GitHub 上有一个存储库,实现了 WebSocket 协议的解码帧。问题是如果同时发送多条消息,浏览器会粘住帧,代码就不能正常工作。

private String DecodeMessageFromClient(Byte[] bytes)
{
    try
    {
        String incomingData = String.Empty;
        Byte secondByte = bytes[1];

        Int32 dataLength = secondByte & 127;
        Int32 indexFirstMask = 2;

        if (dataLength == 126) indexFirstMask = 4;
        else if (dataLength == 127) indexFirstMask = 10;

        IEnumerable<Byte> keys = bytes.Skip(indexFirstMask).Take(4);
        Int32 indexFirstDataByte = indexFirstMask + 4;

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

        return incomingData = Encoding.UTF8.GetString(decoded, 0, decoded.Length);
    }
    catch (Exception ex)
    {
        Debug.WriteLine("Could not decode due to :" + ex.Message);
    }
    return null;
}  

在此处输入图像描述

根据变量的名称,发生这种情况是因为代码跳过了标头,并将其余信息视为帧的内容。但由于消息中有两帧,因此不会跳过第二个标头。

for (Int32 i = indexFirstDataByte, j = 0; i < bytes.Length; i++, j++)
c#
  • 1 1 个回答
  • 10 Views

1 个回答

  • Voted
  1. Best Answer
    Трипольский Пётр
    2020-07-13T20:30:27Z2020-07-13T20:30:27Z

    新代码更难。它接收一个字节数组,从那里选择第一帧并返回未参与解码的剩余字节

    public static byte[] WebSocketBackendMessage(this NetworkStream stream,byte[] bytes,out string message,out WebSocketMessageType type)
    {
        byte oppcode = bytes[0];
        byte shift = 15;
        type = (WebSocketMessageType)(oppcode & shift);
    
        String incomingData = String.Empty;
        Byte secondByte = bytes[1];
        Int32 dataLength = secondByte & 127;
        Int32 indexFirstMask = 2;
        if (dataLength == 126)
        {
            indexFirstMask = 4;
            byte[] newlenght = bytes.Skip(2).Take(2).ToArray();
            Array.Reverse(newlenght);
            dataLength = BitConverter.ToUInt16(newlenght, 0);
        }
        else if (dataLength == 127)
        {
            indexFirstMask = 10;
            throw new Exception("Слишком большой массив информации был отправлен на вебсокет!");
        }
        IEnumerable<Byte> keys = bytes.Skip(indexFirstMask).Take(4);
        Int32 indexFirstDataByte = indexFirstMask + 4;
    
        Byte[] decoded = new Byte[bytes.Length - indexFirstDataByte];
        for (Int32 i = indexFirstDataByte, j = 0; i < indexFirstDataByte + dataLength; i++, j++)
        {
            decoded[j] = (Byte)(bytes[i] ^ keys.ElementAt(j % 4));
        }
    
        message = Encoding.UTF8.GetString(decoded, 0, decoded.Length);
    
        byte[] remain = bytes.Skip(indexFirstDataByte + dataLength).ToArray();
        if (remain.Length == 0) return null;
        else return remain;
    }
    

    它是这样使用的:

    byte[] block = stream.ReadBlock();
    string message = null;
    WebSocketMessageType type;
    
    bool lastFrameEmpty = false;
    while(!lastFrameEmpty)
    {
        lastFrameEmpty = (block = stream.WebSocketBackendMessage(block, out message,out type)) == null;
        if (type == WebSocketMessageType.Text)
        {
            Console.WriteLine("MESSAGE: {0}", message);
        }
        if (type == WebSocketMessageType.Close)
        {
            continueWorking = false;
            break;
        }
    }
    

    以防万一,我将附上读取从浏览器接收到的信息块的扩展代码

    public static byte[] ReadBlock(this NetworkStream stream)
    {
        Byte[] bytes = null;
    
        using (MemoryStream tmp = new MemoryStream())
        {
            byte[] data = new byte[1];
            int readed = -1;
            while (stream.DataAvailable)
            {
                readed = stream.Read(data, 0, data.Length);
                tmp.Write(data, 0, readed);
            }
            if (readed > -1)
            {
                bytes = tmp.ToArray();
            }
        }
        return bytes;
    }
    

    您可以从以下链接下载 Visual Studio 的解决方案:https ://cloud.mail.ru/public/KEeF/H81Q22MXP

    • -1

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    是否可以在 C++ 中继承类 <---> 结构?

    • 2 个回答
  • Marko Smith

    这种神经网络架构适合文本分类吗?

    • 1 个回答
  • Marko Smith

    为什么分配的工作方式不同?

    • 3 个回答
  • Marko Smith

    控制台中的光标坐标

    • 1 个回答
  • Marko Smith

    如何在 C++ 中删除类的实例?

    • 4 个回答
  • Marko Smith

    点是否属于线段的问题

    • 2 个回答
  • Marko Smith

    json结构错误

    • 1 个回答
  • Marko Smith

    ServiceWorker 中的“获取”事件

    • 1 个回答
  • Marko Smith

    c ++控制台应用程序exe文件[重复]

    • 1 个回答
  • Marko Smith

    按多列从sql表中选择

    • 1 个回答
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Suvitruf - Andrei Apanasik 什么是空? 2020-08-21 01:48:09 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5