首页 > 编程语言 >c# socket tcp 通信 结构体 字节流 大端序列 小端序列

c# socket tcp 通信 结构体 字节流 大端序列 小端序列

时间:2023-09-02 15:35:07浏览次数:42  
标签:小端 head c# public Length 序列 new byte Marshal

SeerAGV_2/SeerMessage.cs

using System.Reflection;
using System.Runtime.InteropServices;

namespace SeerAGV
{
    public struct SeerMessageHead
    {
        public byte sync;
        public byte version;
        public ushort number;
        public uint length;
        public ushort type;
#pragma warning disable CS0169 // 禁用 CS0169 警告
        private readonly byte ref0;      //保留
        private readonly byte ref1;      //保留
        private readonly byte ref2;      //保留
        private readonly byte ref3;      //保留
        private readonly byte ref4;      //保留
        private readonly byte ref5;      //保留
#pragma warning restore CS0169 // 启用 CS0169 警告

        public readonly byte[] ToBytes()
        {

            int size = Marshal.SizeOf(this);
            byte[] bytes = new byte[size];

            IntPtr ptr = Marshal.AllocHGlobal(size);
            Marshal.StructureToPtr(this, ptr, true);
            Marshal.Copy(ptr, bytes, 0, size);
            Marshal.FreeHGlobal(ptr);

            if (BitConverter.IsLittleEndian)
            {
                Array.Reverse(bytes, 2, 2);
                Array.Reverse(bytes, 4, 4);
                Array.Reverse(bytes, 8, 2);
            }

            return bytes;
        }


    };


    public struct SeerMessage
    {
        public byte[] head;
        public byte[] body;

        public SeerMessage(SeerMessageHead head, string body)
        {
            this.body = SetBody(body);
            // head中的lenght是body的长度
            head.length = (uint)this.body.Length;
            this.head = head.ToBytes();
        }


        public readonly int Length()
        {
            return body.Length + Marshal.SizeOf(head);
        }


        private static byte[] SetBody(string str)
        {
            byte[] result = new byte[str.Length];
            byte[] buffer = System.Text.Encoding.UTF8.GetBytes(str);
            for (int i = 0; i < buffer.Length; i++)
            {
                result[i] = Convert.ToByte(buffer[i].ToString("X2"), 16);
            }
            return result;
        }
    }
}

SeerAGV_2/SeerAGV.csproj

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net7.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

</Project>

SeerAGV_2/Program.cs

using System.Net.Sockets;
using System.Runtime.InteropServices;

namespace SeerAGV
{

    /// <summary>
    /// 
    /// </summary>
    public class SeerSocket
    {

        /// <summary>
        /// 该方法接受一个十六进制字符串作为参数,并返回一个字节数组。
        /// 它首先使用 `Replace` 方法删除字符串中的所有空格,
        /// 然后检查字符串的长度是否为偶数。如果不是,它会在字符串末尾添加一个空格。
        /// 接下来,它创建一个新的字节数组,并使用 `for` 循环遍历字符串中的每两个字符。
        /// 在循环中,它使用 `Substring` 方法获取当前两个字符,然后使用 `Convert.ToByte` 方法将它们转换为一个字节,并将该字节存储在字节数组中。
        /// 最后,它返回字节数组。
        /// </summary>
        /// <param name="hexString"></param>
        /// <returns></returns>
        private static byte[] HexStrTobyte(string hexString)
        {
            hexString = hexString.Replace(" ", "");
            if (hexString.Length % 2 != 0)
                hexString += " ";

            byte[] returnBytes = new byte[hexString.Length / 2];

            for (int i = 0; i < returnBytes.Length; i++)
            {
                returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2).Trim(), 16);
            }
            return returnBytes;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="bytesBuffer"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentException"></exception>
        public static T BytesToStructure<T>(byte[] bytesBuffer)
        {
            if (bytesBuffer.Length < Marshal.SizeOf(typeof(T)))
            {
                throw new ArgumentException("size error");
            }

            nint bufferHandler = Marshal.AllocHGlobal(bytesBuffer.Length);

            for (int index = 0; index < bytesBuffer.Length; index++)
            {
                Marshal.WriteByte(bufferHandler, index, bytesBuffer[index]);
            }

            // T? structObject = (T)Marshal.PtrToStructure(bufferHandler, typeof(T));
            T? structObject = Marshal.PtrToStructure<T>(bufferHandler);

            Marshal.FreeHGlobal(bufferHandler);

            if (structObject == null)
            {
                throw new InvalidOperationException("Failed to convert bytes to structure.");
            }

            return structObject!;
        }

        /// <summary>
        ///该方法接受一个字符串作为参数,并返回一个字节数组。
        ///它首先创建一个新的字节数组,其长度与输入字符串的长度相同。
        ///然后,它使用 `System.Text.Encoding.UTF8.GetBytes` 方法将输入字符串转换为 UTF-8 编码的字节数组。
        ///接下来,它使用 `for` 循环遍历该字节数组中的每个字节。
        ///在循环中,它使用 `ToString` 方法将当前字节转换为十六进制字符串,并使用 `Convert.ToByte` 方法将该字符串转换为字节,并将该字节存储在结果字节数组中。
        ///最后,它返回结果字节数组。希望这对您有所帮助!
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        private static byte[] NormalStrToHexByte(string str)
        {
            byte[] result = new byte[str.Length];
            byte[] buffer = System.Text.Encoding.UTF8.GetBytes(str);
            for (int i = 0; i < buffer.Length; i++)
            {
                result[i] = Convert.ToByte(buffer[i].ToString("X2"), 16);
            }
            return result;
        }


        public static byte[] SeerMessageHeadToBytes(SeerMessageHead msg)
        {
            var hsize = Marshal.SizeOf(msg);
            byte[] bytes = new byte[hsize];
            nint structPtr = Marshal.AllocHGlobal(hsize);
            Marshal.StructureToPtr(msg, structPtr, false);
            Marshal.Copy(structPtr, bytes, 0, hsize);
            Marshal.FreeHGlobal(structPtr);
            return bytes;
        }




        public static void Send()
        {
            try
            {
                // 创建tcp连接
                var client = new TcpClient("127.0.0.1", 19204);

                if (client.Connected)
                {
                    NetworkStream serverStream = client.GetStream();

                    // 创建一些变量
                    var seerMsg = new SeerMessage(new SeerMessageHead
                    {
                        sync = 0x5a,
                        version = 0x01,
                        number = 0x0001,
                        type = 2002,
                    }, $"{{\"x\":10.0,\"y\":3.0,\"angle\":0}}");
                    serverStream.Write(seerMsg.head, 0, seerMsg.head.Length);
                    serverStream.Write(seerMsg.body, 0, seerMsg.body.Length);
                    serverStream.Flush();



                    byte[] inStream = new byte[16];
                    while (16 != serverStream.Read(inStream, 0, 16))
                    {
                        Thread.Sleep(20);
                    }

                    var recv_head = BytesToStructure<SeerMessageHead>(inStream);
                    byte[] recvbyte = BitConverter.GetBytes(recv_head.length);
                    Array.Reverse(recvbyte);
                    var dsize = BitConverter.ToUInt32(recvbyte, 0);

                    const int bufferSize = 512;
                    var datalist = new List<byte>();
                    int count = 0;

                    while (true)
                    {
                        byte[] buffer = new byte[bufferSize];
                        int readSize = serverStream.Read(buffer, 0, bufferSize);

                        count += readSize;
                        datalist.AddRange(buffer);

                        if (count == dsize)
                        {
                            break;
                        }

                        Thread.Sleep(10);
                    }

                    var content = BitConverter.ToString(SeerMessageHeadToBytes(recv_head)).Replace("-", " ");//normalStrToHexStr(Encoding.UTF8.GetString(seerMessageHeadToBytes(recv_head)));
                    Console.WriteLine(content);


                    string str = System.Text.Encoding.UTF8.GetString(datalist.ToArray());


                    client.Close();
                }
            }
            catch (SocketException)
            {

            }
            catch (IOException)
            {
            }
        }

    }

    /// <summary>
    /// 将socket封装成一个类
    /// </summary>
    public class SocketClient
    {
        // 定义一些私有字段,用于存储客户端、网络流和缓冲区大小等信息
        private TcpClient client;
        private NetworkStream stream;
        private const int bufferSize = 512;

        // 定义一个构造函数,用于创建一个socket客户端,并连接到指定的服务器地址和端口
        public SocketClient(string address, int port)
        {
            client = new TcpClient(address, port);
            if (client.Connected)
            {
                stream = client.GetStream();
            }
            else
            {
                throw new Exception("Failed to connect to the server.");
            }
        }

        // 定义一个Send方法,用于发送一个SeerMessage类型的结构体到服务器
        public void Send(SeerMessage message)
        {
            if (stream != null)
            {
                stream.Write(message.head, 0, message.head.Length);
                stream.Write(message.body, 0, message.body.Length);
                stream.Flush();
            }
            else
            {
                throw new Exception("The network stream is null.");
            }
        }

        // 定义一个Receive方法,用于接收服务器返回的一个SeerMessage类型的结构体
        public string Receive()
        {
            if (stream != null)
            {
                // 接收消息头
                byte[] headBytes = new byte[16];
                while (16 != stream.Read(headBytes, 0, 16))
                {
                    Thread.Sleep(20);
                }
                var head = BytesToStructure<SeerMessageHead>(headBytes);

                // 接收消息体
                byte[] lengthBytes = BitConverter.GetBytes(head.length);
                Array.Reverse(lengthBytes);
                var bodyLength = BitConverter.ToUInt32(lengthBytes, 0);

                var bodyList = new List<byte>();
                int count = 0;

                while (true)
                {
                    byte[] buffer = new byte[bufferSize];
                    int readSize = stream.Read(buffer, 0, bufferSize);

                    count += readSize;
                    bodyList.AddRange(buffer);

                    if (count == bodyLength)
                    {
                        break;
                    }

                    Thread.Sleep(10);
                }

                var body = bodyList.ToArray();


                // 返回消息
                return BitConverter.ToString(body);

            }
            else
            {
                throw new Exception("The network stream is null.");
            }
        }

        public static T BytesToStructure<T>(byte[] bytesBuffer)
        {
            if (bytesBuffer.Length < Marshal.SizeOf(typeof(T)))
            {
                throw new ArgumentException("size error");
            }

            nint bufferHandler = Marshal.AllocHGlobal(bytesBuffer.Length);

            for (int index = 0; index < bytesBuffer.Length; index++)
            {
                Marshal.WriteByte(bufferHandler, index, bytesBuffer[index]);
            }

            // T? structObject = (T)Marshal.PtrToStructure(bufferHandler, typeof(T));
            T? structObject = Marshal.PtrToStructure<T>(bufferHandler);

            Marshal.FreeHGlobal(bufferHandler);

            if (structObject == null)
            {
                throw new InvalidOperationException("Failed to convert bytes to structure.");
            }

            return structObject!;
        }


    }



    class Program
    {
        static void Main(string[] args)
        {
            var myObject = new SeerSocket();
            SeerSocket.Send();

        }
    }

}

标签:小端,head,c#,public,Length,序列,new,byte,Marshal
From: https://www.cnblogs.com/zhuoss/p/17673722.html

相关文章

  • 排查国标GB28181视频监控平台EasyGBS无法播放且抓包返回ICMP的步骤
    GB28181视频平台EasyGBS是一个基于国标GB28181协议的视频云服务平台。它支持多路设备同时接入,并能将视频流以RTSP、RTMP、FLV、HLS、WebRTC等格式分发给多个平台和终端。该平台提供视频监控直播、云端录像、云存储、检索回放、智能告警以及语音对讲等功能。在视频能力方面,EasyGBS支......
  • 国标GB28181视频平台LiteCVR使用时出现自动删除云端录像怎么回事
    近期,我们整理并汇总了以前使用者在使用LiteCVR视频汇聚平台时遇到的技术问题反馈。为了方便大家参考,我们将逐步分享根据使用者反馈和问题描述的技术问题的解决方法及优化步骤。根据使用者的反馈,设备录像功能出现了异常。虽然设备进行了半小时的录制,但在平台上只有最近一两分钟的录......
  • EasyCVR安防视频监控平台实现环卫车的车载视频为环卫提供助力
    随着社会的不断进步和发展,文明已经成为社会精神的重要标志。为了提升城市卫生管理水平,加强基础设施项目建设,并有效控制道路扬尘,科学合理地调度和管理车辆,监督环卫作业效果、环卫车辆、环卫设施以及废弃物的处理,全程监控卫生环境,旨在及时发现并快速解决环卫作业问题。在城市文明道路......
  • LED车灯IC降压恒流驱动AP5103大功率95%高效率深度调光摩托车灯芯片
    产品描述AP5103是一款效率高,稳定可靠的LED灯恒流驱动控制芯片,内置高精度比较器,固定关断时间控制电路,恒流驱动电路等,特别适合大功率LED恒流驱动。AP5103采用ESOP8封装,散热片内置接SW脚,通过调节外置电流检测的电阻值来设置流过LED灯的电流,支持外加电压线性调光,最大电流......
  • 无涯教程-JavaScript - FLOOR函数
    描述FLOOR函数将数字向下舍入为零,直到最接近的有效倍数。语法FLOOR(number,significance)争论Argument描述Required/OptionalNumberThenumericvalueyouwanttoround.RequiredSignificanceThemultipletowhichyouwanttoround.RequiredNotes如果数......
  • centos查看mysql默认密码和修改密码
    1、查看mysql默认密码:grep‘temporarypassword’/var/log/mysqld.logroot@localhost:b_1sZou9FZrtb_1sZou9FZrt就是2、修改mysql密码:ALTERUSER‘root’@‘localhost’IDENTIFIEDBY‘newpassword’;‘newpassword’替换成你要设置的密码,注意:密码设置必须要大小写字母数......
  • LED摩托车灯驱动ICAP5160降压恒流芯片输出8A大电流
    产品描述AP5160是一款效率高,稳定可靠的LED灯恒流驱动控制芯片,内置高精度比较器,固定关断时间控制电路,恒流驱动电路等,特别适合大功率LED恒流驱动。AP5160采用SOT23-6封装,通过调节外置电流检测的电阻值来设置流过LED灯的电流,从而设置LED灯的亮度,外驱MOS管最大输出电流......
  • 【WCH蓝牙系列芯片】-基于CH582开发板—基础外设输出PWM波形讲解
    ---------------------------------------------------------------------------------------------------------------------------------------------------------------------在WCH官方提供的CH583的EVT资源包中,我们可以找到PWMX的例程,这是一个8位的PWM输出,占空比和周期可调的......
  • Spack:软件包管理的终极解决方案 以 unzip 无sudo权限安装为例
    Spack是一个高度可配置的软件包管理工具,旨在支持各种软件栈的安装和管理。尽管最初是为高性能计算设计的,但Spack的灵活性和扩展性使其也能在多种计算环境中派上用场,包括个人电脑和云基础设施。初始化和配置在Ubuntu下的安装和配置克隆Spack仓库使用以下命令从GitHu......
  • 使用SizeBench分析Exe文件体积
    本文将介绍微软开源免费的SizeBench工具,使用SizeBench工具可以用来分析Exe二进制文件的体积,分析Exe文件大小里面有哪些是可以优化的下载安装方式:请前往应用商店安装,应用商店地址:https://www.microsoft.com/store/productId/9NDF4N1WG7D6工具的开源项目地址:https://gith......