当前位置: 首页 > news >正文

字节序处理和消息队列的控制

文章目录字节序的问题区分本机字节序使用网络字节序消息队列控制字节序的问题在计算机网络中由于不同的计算机使用的 CPU 架构和字节顺序可能不同因此在传输数据时需要对数据的字节序进行统一以保证数据能够正常传输和解析。这就是网络字节序的作用。具体来说计算机内部存储数据的方式有两种大端序Big-Endian和小端序Little-Endian。在大端序中高位字节存储在低地址处而低位字节存储在高地址处。在小端序中高位字节存储在高地址处而低位字节存储在低地址处。:::color1⚠️**在网络通信过程中通常使用的是大端序**。这是因为早期的网络硬件大多采用了 Motorola 处理器而 Motorola 处理器使用的是大端序。此外大多数网络协议规定了网络字节序必须为大端序。因此在进行网络编程时需要将主机字节序转换为网络字节序也就是将数据从本地字节序转换为大端序。可以使用诸如 htonl、htons、ntohl 和 ntohs 等函数来实现字节序转换操作。综上所述网络字节序的主要作用是统一不同计算机间的数据表示方式以保证数据在网络中的正确传输和解析。:::区分本机字节序#includeiostreamusingnamespacestd;// 判断当前系统的字节序是大端序还是小端序boolis_big_endian(){// 定义一个整型变量 num 并赋值为 1。在内存中它的十六进制表示为 0x00000001intnum1;// (char*)num: 强行将 int 型变量的地址转换为 char* 类型的指针// 这样指针就会指向该整型变量在内存中占据的【最低字节地址】首地址。// *: 解引用该 char* 指针从而只取出这一个字节8位的值。if(*(char*)num1){// 如果最低字节地址处存储的值是 1说明低位数据存储在了低地址处// 当前系统为小端序returnfalse;}else{// 如果最低字节地址处存储的值是 0说明高位数据存储在了低地址处// 当前系统为大端序returntrue;}}intmain(){// 定义一个 4 字节的整型变量其十六进制值为 0x12345678// 其中 12 是高位字节78 是低位字节intnum0x12345678;// 获取 num 的首地址并转换为字节指针 char*以便后续能逐字节访问内存char*p(char*)num;// 以十六进制hex形式打印出原始数据cout原始数据hexnumendl;// 根据自定义函数的返回值进入不同的打印逻辑if(is_big_endian()){cout当前系统为大端序endl;cout字节序为;// 大端序高位字节存放在低地址起始地址低位字节存放在高地址。// 因此直接从内存低地址向高地址正向遍历i 从 0 到 3即可按逻辑顺序输出 12 34 56 78for(inti0;isizeof(num);i){// (int)*(p i): 移动字节指针解引用取出该字节并强转为 int 供 cout 以十六进制打印couthex(int)*(pi) ;}coutendl;}else{cout当前系统为小端序endl;cout字节序为;// 小端序低位字节存放在低地址起始地址高位字节存放在高地址。// 在小端内存中实际存储顺序为78 56 34 12。// 为了在控制台能按人类阅读习惯正向显示出 12 34 56 78// 这里采用了逆序遍历i 从 3 减小到 0即先从高地址存放12的地方开始向前打印。for(intisizeof(num)-1;i0;i--){// (int)*(p i): 倒序移动字节指针解引用取出该字节并强转为 int 打印couthex(int)*(pi) ;}coutendl;}return0;}:::info在上述代码中使用了一个 is_big_endian() 函数来判断当前系统的字节序是否为大端序。该函数通过创建一个整型变量 num并将其最低位设置为 1然后通过指针强制转换成字符指针判断第一个字节是否为 1 来判断当前系统的字节序。在 main 函数中定义了一个整型变量 num并将其初始化为 0x12345678。接着使用 char* 类型的指针 p 来指向 num 的地址。然后通过判断当前系统的字节序来输出 num 的字节序。如果当前系统为大端序则按照原始顺序输出各个字节如果当前系统为小端序则需要逆序输出各个字节。:::原始数据12345678 当前系统为大端序 字节序为12345678原始数据12345678 当前系统为小端序 字节序为78563412使用网络字节序为保证字节序一致性网络传输使用网络字节序也就是大端模式。在 boost::asio 库中可以使用boost::asio::detail::socket_ops::host_to_network_long()和boost::asio::detail::socket_ops::host_to_network_short()函数将主机字节序转换为网络字节序。具体方法如下#includeboost/asio.hpp#includeiostreamintmain(){// 定义一个本地主机字节序的 32 位4字节无符号整数// 十六进制表示为 0x12345678uint32_thost_long_value0x12345678;// 定义一个本地主机字节序的 16 位2字节无符号整数// 十六进制表示为 0x5678常用于 TCP/UDP 端口号或 2 字节的包头长度uint16_thost_short_value0x5678;// 【4字节转换主机序 - 网络序】// 调用 Boost.Asio 底层函数将 32 位长整数转换为网络字节序即大端序 Big-Endian。// 如果当前系统本身就是大端序此函数什么都不做如果是小端序如 Intel x86/x64它会把字节顺序完全颠倒变成 0x78563412。uint32_tnetwork_long_valueboost::asio::detail::socket_ops::host_to_network_long(host_long_value);// 【2字节转换主机序 - 网络序】// 将 16 位短整数转换为网络字节序。// 在小端序系统上转换后字节会发生对调变成 0x7856。uint16_tnetwork_short_valueboost::asio::detail::socket_ops::host_to_network_short(host_short_value);// 以十六进制std::hex格式打印出转换前后的对比结果std::coutHost long value: 0xstd::hexhost_long_valuestd::endl;std::coutNetwork long value: 0xstd::hexnetwork_long_valuestd::endl;std::coutHost short value: 0xstd::hexhost_short_valuestd::endl;std::coutNetwork short value: 0xstd::hexnetwork_short_valuestd::endl;return0;}在上述代码中分别将 32 位和 16 位的主机字节序数值转换为网络字节序并输出转换结果。需要注意的是在使用这些函数时应该确保输入参数和返回结果都是无符号整数类型否则可能会出现错误。同样的道理**我们只需要在服务器发送数据时将数据长度转化为网络字节序在接收数据时将长度转为本机字节序**。shortdata_len0;memcpy(data_len,_recv_head_node-_data,HEAD_LENGTH);//网络字节序转化为本地字节序data_lenboost::asio::detail::socket_ops::network_to_host_short(data_len);coutdata_len is data_lenendl;MsgNode(char*msg,shortmax_len):_total_len(max_lenHEAD_LENGTH),_cur_len(0){_datanewchar[_total_len1]();//转为网络字节序intmax_len_hostboost::asio::detail::socket_ops::host_to_network_short(max_len);memcpy(_data,max_len_host,HEAD_LENGTH);memcpy(_dataHEAD_LENGTH,msg,max_len);_data[_total_len]\0;}客户端也遵循同样的处理。消息队列控制发送时我们会将发送的消息放入队列里以保证发送的时序性每个session都有一个发送队列因为有的时候发送的频率过高会导致队列增大所以要对队列的大小做限制当队列大于指定数量的长度时就丢弃要发送的数据包以保证消息的快速收发。voidCSession::Send(char*msg,intmax_length){// 【加锁保护】使用互斥锁的 RAII 机制进行自动加锁// 保护发送队列 _send_que防止多线程同时调用 Send 导致队列数据损坏因为 STL 队列不是线程安全的std::lock_guardstd::mutexlock(_send_lock);// 获取当前发送队列中已经积压的数据包数量intsend_que_size_send_que.size();// 【流量控制/防爆内存】如果队列中的包数量已经超过了设定的最大限制MAX_SENDQUEif(send_que_sizeMAX_SENDQUE){// 打印错误日志警告该会话的发送队列已满coutsession: _uuid send que fulled, size is MAX_SENDQUEendl;// 直接拒绝本次发送请求丢弃该数据包并返回防止内存被无限制撑爆return;}// 【入队缓存】将本次需要发送的数据包装成智能指针包裹的内存节点MsgNode并推入发送队列末尾_send_que.push(make_sharedMsgNode(msg,max_length));// 【状态判定】// 如果 send_que_size 0说明在本次数据入队之前队列里就已经有旧的数据包在排队了。// 这意味着底层必然已经有一个正在执行的 async_write 异步写操作在内核中挂起。if(send_que_size0){// 当前线程只需要把数据放入队列即可后续的 HandleWrite 回调会自动消费新入队的包因此直接返回return;}// 【主动点火触发】// 如果 send_que_size 等于 0说明此前队列为空底层没有处于挂起状态的异步写操作。// 此时必须由当前调用 Send 的线程主动“点火”触发第一次异步写操作。automsgnode_send_que.front();// 【异步全量写】调用 async_write 将队列头部的节点数据异步发送出去// 绑定 SharedSelf() 增加会话的智能指针引用计数确保在异步发送中途 CSession 节点不会被销毁boost::asio::async_write(_socket,boost::asio::buffer(msgnode-_data,msgnode-_total_len),std::bind(CSession::HandleWrite,this,std::placeholders::_1,SharedSelf()));}
http://www.zskr.cn/news/1396358.html

相关文章:

  • StPageFlip:开源JavaScript翻页动画库的深度技术解析与最佳实践
  • pypto:用Python直接写NPU算子,门槛有多低?
  • AIPP硬件预处理:比OpenCV快多少?
  • 2026年游戏电竞椅推荐:拓际TGIF舒适出众 - 17322238651
  • FPGA边缘AI设计空间探索:MathWorks HDL工具箱实测与避坑指南
  • 淘宝客APP源码-自营商城任务墙源码美团外卖CPS广告联的技术难点
  • FPGA硬件加速高光谱异常检测:嵌入式实时处理架构与优化实践
  • 随机数值线性代数在大规模矩阵计算中的应用与优化
  • 如何高效管理B站内容?BilibiliDown跨平台下载方案详解
  • 魔兽争霸3终极优化指南:如何用WarcraftHelper开源工具轻松提升游戏性能
  • 告别光阱能量不均:用Python复现加权GSW算法,手把手教你优化全息光镊
  • 3步搞定:微信聊天记录永久保存的实用方案
  • 影像技术实战27:图片压缩到指定大小不失真?质量二分搜索 + 尺寸兜底方案
  • 迁移学习与通用势函数驱动的高通量材料筛选工作流实践
  • VMware装Linux避坑大全:从CentOS网络连接到Ubuntu中文乱码,一次解决
  • Linux 负载均衡的 task_h_load:任务层级负载计算
  • 2026年电竟椅品牌哪款好:拓际TGIF臻品之选 - 17322238651
  • 告别环境报错:手把手教你解决OpenCDA在Windows安装中的三大常见问题(Carla导入/PyTorch版本/SUMO路径)
  • Unity地形纹理混合太卡?试试MTE的贴图数组功能(支持最多12层材质)
  • CVE编号规范与漏洞生命周期管理指南
  • 告别混乱状态机!用UE4行为树+黑板实现智能敌人AI(实战案例解析)
  • 号易推广手机卡可靠吗?实测靠谱但是第一步注册很重要(详细说代理手机卡副业) - 流量卡代理招商
  • 深圳劳动仲裁机构选择:2026年度头部机构多档位解读 - 资讯速览
  • 基于近似熵剖面无模型估计动态噪声功率的原理与实践
  • Claude Code 必备 Skill 清单:14 个亲测好用的效率技能包,一键安装全部
  • HR 笑着问我前同事:“他上次迟到是因为堵车,还是因为宿醉?”
  • RecBERT:基于领域自适应与查询分割的语义推荐系统实战
  • Schema 结构化数据:GEO 被引用的核心开关
  • 在多模型项目开发中利用Taotoken模型广场进行快速选型与切换
  • Taotoken用量看板如何帮助开发者清晰掌控月度API支出