物联网项目-温湿度表结构

物联网项目-温湿度-Web后台

物联网项目-服务端TCP Server

物联网项目-订阅者Subscribe

物联网项目-温湿度之 TCP 协议包C#版

物联网项目-通讯协议之 C语言版 STM32

物联网项目-通讯协议之 Java版

物联网项目-温湿度之 nodemcu esp8266 刷机

物联网项目-温湿度stm32 发送短信打电话


0、背景

本协议包参考车联网TCP 组包格式,C#写测试客户端。

1、代码

主函数

static void Main(string[] args)
        {
            //TestData.LoginData();
            //TestData.PostData();
            //Console.ReadLine();
            //return;
            byte[] re;
            
            MyTcpClient.Connect();
            
            
            Console.WriteLine("输入任意字符并回车用以发送登录数据 >");
            Console.ReadLine();
            //send//向服务器端发送消息
            re = System.Text.Encoding.ASCII.GetBytes(TestData.LoginData());
            //re = StringTool.strToToHexByte(TestData.LoginData());
            MyTcpClient.SendMsg(re);
            Console.WriteLine("登录发送完毕");
            Console.WriteLine("输入任意字符并回车用以发送检测数据 >");
            Console.ReadLine();
            for(int i = 0; i < 5; i++)
            {
                //re = StringTool.strToToHexByte(TestData.PostData());
                re = System.Text.Encoding.ASCII.GetBytes(TestData.PostData());
                MyTcpClient.SendMsg(re);
                Thread.Sleep(2000);//不加这个会粘包
            }
            Console.WriteLine("输入任意字符并回车用以发送检测数据 >");
            Console.ReadLine();
            //客户端发送消息登出 主动关闭连接
        }

Tcp Client

public class MyTcpClient
    {
        static int defaultPort = 7738;
        static string defaultIp = "10.1.31.31";

        private static Socket clientSocket = null;
        private static Thread thread = null;
        /// <summary>
        /// 连接服务器端
        /// </summary>
        public static void Connect()
        {
            int.TryParse(System.Configuration.ConfigurationManager.AppSettings["serverport"], out defaultPort);
            if (false == string.IsNullOrEmpty(System.Configuration.ConfigurationManager.AppSettings["serverip"]))
            {
                defaultIp = System.Configuration.ConfigurationManager.AppSettings["serverip"];
            }
            clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPAddress ip = IPAddress.Parse(defaultIp);
            IPEndPoint endPoint = new IPEndPoint(ip, defaultPort);
            clientSocket.Connect(endPoint);
            thread = new Thread(ReceMsg);
            thread.IsBackground = true;
            thread.Start();
        }
        /// <summary>
        /// 接收服务器端数据
        /// </summary>
        private static void ReceMsg()
        {
            while (true)
            {
                try
                {
                    byte[] buffer = new byte[1024];
                    int length = clientSocket.Receive(buffer);
                    Console.WriteLine("连接状态:" + clientSocket.Connected);
                    if (clientSocket.Connected == false)
                    {
                        return;
                    }
                    byte[] buf = new byte[length];
                    Array.Copy(buffer, buf, length);
                    Console.WriteLine("接收消息>");
                    Console.WriteLine(System.Text.Encoding.ASCII.GetString(buf));// StringTool.byteToHexStr(buf));
                }catch(SocketException ex)
                {
                    Console.WriteLine(ex.Message);
                    if (ex.ErrorCode == 10054)
                    {
                        return;
                    }
                }
            }
        }

        public static void SendMsg(string msg)
        {
            clientSocket.Send(Encoding.ASCII.GetBytes(msg));
        }

        public static void SendMsg(byte[] buffer)
        {
            clientSocket.Send(buffer);
        }
    }

组包测试

public class TestData
    {
        public static string LoginData()
        {
            string head = StringTool.StringToHexString("##", UTF8Encoding.ASCII);//0 起始符号
            string cmd = "";
            cmd += "01";//2 命令标识
            cmd += "FE";//3 应答标志
            cmd += StringTool.StringToHexString("SKYWELLIT00000003", UTF8Encoding.ASCII).ToUpper();//4 唯一识别码 主板程序编号

            cmd += "01";//21 数据单元加密方式 01 不加密

            string dataLength = ""; //22 数据单元长度 WORD
            string data = "";
            DateTime dt = DateTime.Now;
            data += Convert.ToString(19, 16).PadLeft(2, '0');
            data += Convert.ToString(dt.Month, 16).PadLeft(2, '0');
            data += Convert.ToString(dt.Day, 16).PadLeft(2, '0');
            data += Convert.ToString(dt.Hour, 16).PadLeft(2, '0');
            data += Convert.ToString(dt.Minute, 16).PadLeft(2, '0');
            data += Convert.ToString(dt.Second, 16).PadLeft(2, '0');

            string s2 = Convert.ToString(2001, 16).ToUpper();//登录流水号
            s2 = s2.PadLeft(4, '0');
            data += s2;

            data += StringTool.StringToHexString("898600MFSSYYGXXXXX03", Encoding.ASCII).ToUpper();

            data += StringTool.StringToHexString("1", UTF8Encoding.ASCII); //温度
            data += StringTool.StringToHexString("1", UTF8Encoding.ASCII); //湿度
            data += StringTool.StringToHexString("0", UTF8Encoding.ASCII); //烟雾
            data += StringTool.StringToHexString("0", UTF8Encoding.ASCII); //水浸
            data += StringTool.StringToHexString("0", UTF8Encoding.ASCII);//电力
            data += StringTool.StringToHexString("0", UTF8Encoding.ASCII);//入侵
            dataLength = Convert.ToString(data.Length, 16);
            Console.WriteLine(dataLength);
            dataLength = dataLength.PadLeft(4, '0');
            string check = StringTool.GetBCCXorCode(StringTool.strToToHexByte(cmd + dataLength + data));
            string s = head + cmd + dataLength + data + check;
            return s;
        }

        public static string PostData()
        {
            string head = StringTool.StringToHexString("##", UTF8Encoding.ASCII);//0 起始符号
            string cmd = "";
            cmd += "02";//2 命令标识 01 登录 02 实时信息上报
            cmd += "FE";//3 应答标志
            cmd += StringTool.StringToHexString("SKYWELLIT00000003", UTF8Encoding.ASCII);//4 唯一识别码 主板程序编号

            cmd += "01";//21 数据单元加密方式 01 不加密

            string dataLength = ""; //22 数据单元长度 WORD
            string data = "";
            DateTime dt = DateTime.Now;
            
            data += Convert.ToString(19, 16).PadLeft(2, '0');
            data += Convert.ToString(dt.Month, 16).PadLeft(2, '0');
            data += Convert.ToString(dt.Day, 16).PadLeft(2, '0');
            data += Convert.ToString(dt.Hour, 16).PadLeft(2, '0');
            data += Convert.ToString(dt.Minute, 16).PadLeft(2, '0');
            data += Convert.ToString(dt.Second, 16).PadLeft(2, '0');
            
            data += "01";
            data += Convert.ToString(22).PadLeft(2, '0').PadRight(4,'0'); //温度
            data += "02";
            data += Convert.ToString(28).PadLeft(2, '0').PadRight(4, '0'); //湿度
            
            dataLength = Convert.ToString(data.Length, 16);
            dataLength = dataLength.PadLeft(4, '0');
            string check = StringTool.GetBCCXorCode(StringTool.strToToHexByte(cmd + dataLength + data));
            string s = head + cmd + dataLength + data + check;
            return s;
        }
    }
    
    public class StringTool
    {
        /// <summary>
        /// 将字符串转为16进制字符,允许中文
        /// </summary>
        /// <param name="s"></param>
        /// <param name="encode"></param>
        /// <returns></returns>
        public static string StringToHexString(string s, Encoding encode)
        {
            byte[] b = encode.GetBytes(s);//按照指定编码将string编程字节数组
            string result = string.Empty;
            for (int i = 0; i < b.Length; i++)//逐字节变为16进制字符
            {
                result += Convert.ToString(b[i], 16);
            }
            return result;
        }
        /// <summary>
        /// 将16进制字符串转为字符串
        /// </summary>
        /// <param name="hs"></param>
        /// <param name="encode"></param>
        /// <returns></returns>
        public static string HexStringToString(string hs, Encoding encode)
        {
            string strTemp = "";
            byte[] b = new byte[hs.Length / 2];
            for (int i = 0; i < hs.Length / 2; i++)
            {
                strTemp = hs.Substring(i * 2, 2);
                b[i] = Convert.ToByte(strTemp, 16);
            }
            //按照指定编码将字节数组变为字符串
            return encode.GetString(b);
        }
        /// <summary>
        /// 将byte[]转为16进制字符串
        /// </summary>
        /// <param name="bytes"></param>
        /// <returns></returns>
        public static string byteToHexStr(byte[] bytes)
        {
            string returnStr = "";
            if (bytes != null)
            {
                for (int i = 0; i < bytes.Length; i++)
                {
                    returnStr += bytes[i].ToString("X2");
                }
            }
            return returnStr;
        }

        /// <summary>
        /// 将16进制的字符串转为byte[]
        /// </summary>
        /// <param name="hexString"></param>
        /// <returns></returns>
        public static byte[] strToToHexByte(string hexString)
        {
            hexString = hexString.Replace(" ", "");
            if ((hexString.Length % 2) != 0)
                hexString = "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), 16);
            return returnBytes;
        }

        /// <summary>
        /// BCC和校验代码返回16进制
        /// </summary>
        /// <param name="data">需要校验的数据包</param>
        /// <returns></returns>
        public static string GetBCCXorCode(byte[] data)
        {
            byte CheckCode = 0;
            int len = data.Length;
            for (int i = 0; i < len; i++)
            {
                CheckCode ^= data[i];
                System.Console.WriteLine(data[i]);
            }
            System.Console.WriteLine(CheckCode);
            return Convert.ToString(CheckCode, 16).ToUpper();
        }

        /// <summary>
        /// BCC和校验代码
        /// </summary>
        /// <param name="data">需要校验的数据包</param>
        /// <returns></returns>
        public static byte Get_CheckXor(byte[] data)
        {
            byte CheckCode = 0;
            int len = data.Length;
            for (int i = 0; i < len; i++)
            {
                CheckCode ^= data[i];
            }
            return CheckCode;
        }
    }