zoukankan      html  css  js  c++  java
  • 完整的Socket代码

    先上图

    列举一个通信协议

    网关发送环境数据

     此网关设备所对应的所有传感器参数,格式如下:

    网关发送:

    包长度+KEY+请求类型+发送者+接收者+消息类型+消息内容

    说明:

    包长度:short int型(16位),除本字段外,后面所跟的所有数据字节数;

    标识符:int32型,固定值:0x987656789;

    请求类型:int32型,数据通信:3;

    发送者:string,终端编号,如:11170303001,格式:长度(int)+发送者字符串的Unicode编码(长度是指发送者的Unicode编码后的字节数);

    接收者:string,服务器编号,如:server,格式:长度(int)+发送者字符串的Unicode编码(长度是指发送者的Unicode编码后的字节数);

    消息内型:int32型,当前环境参数:146;

    消息内容:所有控制口开关状态及环境参数,其格式如下

    输出状态+输入状态+传感器数量N+传感器数据 * N

    说明

    输出状态:控制器开关量输出状态,long 型(64位),此变量每一位表示一个开关的状态,1表示开,0表示关;

    输入状态:控制器开关量输入状态,long 型(64位),此变量每一位表示一个输入的状态,1表示有输入,0表示无输入。最低位用于手自动状态指示。

    传感器数量:byte型,指的是传感器数量

    传感器数据:格式为:位置+类型+地址+参数个数+数据

    说明

    位置:byte型,表示此组传感器所摆放位置;如:1表示放置点为1区;

    类型:byte

    地址:byte型,此组传感器的地址,每个终端所管理的传感器中不能有重复地址;

    参数个数:byte,每个参数对应一个Float数据

    数据: float数组,数组元素个数由参数个数决定

    服务器应答:

    包长度+KEY+应答类型

     数据包长度:int16,除本字段外其他所有字段的字节                                     总数;

     KEY值:int32,值=123454321;

          应答类型:int32,值=100:发送成功,可根据此应答                       判断客户端是否在线

    //---------------------------------------------------------------------------------我是华丽的分割线--------------------------------------------------------------------------------------------------

    核心代码

     public class StaticUdpDal
        {
            private static Socket socket = null;
    
            private bool IsRun = true, _IsSuccse = false;
            private int num = 0, recNum;
            private int _LoopNum = 3;//循环计数器和循环等待次数
            private bool _IsReadMsgType = true;//是否读取消息类型
    
            public int LoopNum
            {
                get { return _LoopNum; }
                set { _LoopNum = value; }
            }
            private EndPoint point;
    
            /// <summary>
            ///  是否成功收到消息
            /// </summary>
            public bool IsSuccse
            {
                get { return _IsSuccse; }
                set { _IsSuccse = value; }
            }
            private ProtocolModel pModel;
            /// <summary>
            /// 数据发送接收之间需要的数据模型
            /// </summary>
            public ProtocolModel PModel
            {
                get { return pModel; }
                set { pModel = value; }
            }
    
            private MemoryStream sendStream;
    
            /// <summary>
            /// //发送内容
            /// </summary>
            public MemoryStream SendStream
            {
                get { return sendStream; }
                set { sendStream = value; }
            }
    
            /// <summary>
            /// 是否读取消息类型,默认读取
            /// </summary>
            public bool IsReadMsgType
            {
                get { return _IsReadMsgType; }
                set { _IsReadMsgType = value; }
            }
    
            public StaticUdpDal()
            {
                //绑定IP端口
                if (socket == null)
                {
                    socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
                    socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
    
                    string UdpSendIP = ConfigurationManager.AppSettings["UdpSendIP"].ToString();
                    string UdpSendPort = ConfigurationManager.AppSettings["UdpSendPort"].ToString();
    
                    IPEndPoint ipep = new IPEndPoint(string.IsNullOrWhiteSpace(UdpSendIP) ? IPAddress.Any : IPAddress.Parse(UdpSendIP),
                        string.IsNullOrWhiteSpace(UdpSendPort) ? 50090 : int.Parse(UdpSendPort));//本机预使用的IP和端口
                    socket.Bind(ipep);
                }
            }
    
            /// <summary>
            /// UDP发送接收主函数
            /// </summary>
            public BinaryReader UdpMain()
            {
                Task<BinaryReader> taskRecive = Task<BinaryReader>.Factory.StartNew(() => ReciveMsg());
                Task taskSend = Task.Factory.StartNew(() => sendMsg());
    
                taskRecive.Wait();
                return taskRecive.Result;
            }
            /// <summary>
            /// 向特定ip的主机的端口发送数据报
            /// </summary>
            public void sendMsg()
            {
                while (true)
                {
                    if (num >= _LoopNum || !IsRun)
                    {
                        IsRun = false;
                        return;
                    }
                    num++;
    
                    try
                    {
                        byte[] buffer = sendStream.ToArray();
                        point = new IPEndPoint(IPAddress.Parse(pModel.DisplayIP), pModel.DisplayPort);
                        socket.SendTo(buffer, buffer.Length, SocketFlags.None, point);//发送
                    }
                    catch (Exception ex)
                    {
                        ZP.Comm.ErrHandler.WriteError(ex, "UDP通信异常-发送");
                        IsRun = false; return;
                    }
                    Thread.Sleep(1000);//时间间隔为1秒
                }
    
            }
    
            /// <summary>
            /// 接收发送给本机ip对应端口号的数据报
            /// </summary>
            public BinaryReader ReciveMsg()
            {
                byte[] data = new byte[1500];
    
                while (true)
                {
                    recNum++;
                    if (recNum > 30 || !IsRun) // 3秒未接收到消息,或标记变为停止,停止
                    {
                        IsRun = false;
                        return null;
                    }
    
                    if (socket == null || socket.Available < 1)
                    { Thread.Sleep(200); continue; }
                    try
                    {
                        int len = socket.Receive(data);//接收  socket.Receive(data,SocketFlags.None);  //
                    }
                    catch (Exception ex)
                    {
                        // 在出现未处理的错误时运行的代码
                        ZP.Comm.ErrHandler.WriteError(ex, "UDP通信异常-接收");
                        IsRun = false; return null;
                    }
    
                    BinaryReader reader = GetReciveData(data);//基础判断
                    if (!_IsSuccse)
                    { Thread.Sleep(200); continue; }
    
                    //socket.Close();
                    IsRun = false;//修改运行标记
                    return reader;
                }
            }
    
            /// <summary>
            /// 根据模型获取基础发送内容
            /// </summary>
            /// <returns></returns>
            public MemoryStream GetBaseContent(ProtocolModel _pModel)
            {
                pModel = _pModel;
                sendStream = new MemoryStream();
                BinaryWriter writer = new BinaryWriter(sendStream);
    
                writer.Write(System.Net.IPAddress.HostToNetworkOrder((short)0));//长度
                writer.Write(System.Net.IPAddress.HostToNetworkOrder((int)pModel.Key));//key
                writer.Write(System.Net.IPAddress.HostToNetworkOrder((int)pModel.TalkType));//请求类型
    
                writer.Write(System.Net.IPAddress.HostToNetworkOrder((int)pModel.Sender.Length * 2));//发送者
                writer.Write(Encoding.BigEndianUnicode.GetBytes(pModel.Sender));
    
                writer.Write(System.Net.IPAddress.HostToNetworkOrder((int)pModel.Receiver.Length * 2));//接收者
                writer.Write(Encoding.BigEndianUnicode.GetBytes(pModel.Receiver));
    
                writer.Write(System.Net.IPAddress.HostToNetworkOrder((int)pModel.MsgType));//消息类型
                if (pModel.UseType == 2)
                {
                    writer.Write(System.Net.IPAddress.HostToNetworkOrder((int)pModel.DisplayNo.Length * 2)); //终端编号 日光温室
                    writer.Write(Encoding.BigEndianUnicode.GetBytes(pModel.DisplayNo));
                }
    
                return sendStream;
            }
    
            /// <summary>
            /// 根据当前模型,获取接受信息
            /// </summary>
            /// <param name="data"></param>
            /// <returns></returns>
            public BinaryReader GetReciveData(byte[] data)
            {
                MemoryStream stream2 = new MemoryStream(data);
                BinaryReader reader = new BinaryReader(stream2);
    
                short packageLen = System.Net.IPAddress.NetworkToHostOrder(reader.ReadInt16());//长度
    
                int key = System.Net.IPAddress.NetworkToHostOrder(reader.ReadInt32());//key
                if (!((!pModel.IsConServer && key == (int)GhMsgEnum.Key) || (pModel.IsConServer && key == (int)GhMsgEnum.Key1)))//987656789  123454321
                    return reader;
                //-----------------------------------------不同的地方--------------------------------------------------
                int replyKind = System.Net.IPAddress.NetworkToHostOrder(reader.ReadInt32());//回复的类型 3
                if (replyKind != PModel.AnswerType)//3
                    return reader;
                int senderLen = System.Net.IPAddress.NetworkToHostOrder(reader.ReadInt32());//发送者的长度
                byte[] temp = new byte[1024];
                temp = reader.ReadBytes(senderLen);
                string No = Encoding.BigEndianUnicode.GetString(temp);
    
                int receiveLen = System.Net.IPAddress.NetworkToHostOrder(reader.ReadInt32());//接收者的长度
                string receive;
                if (receiveLen > 0)
                    receive = Encoding.BigEndianUnicode.GetString(reader.ReadBytes(receiveLen));
                //-----------------------------------------不同的地方--------------------------------------------------
                if (IsReadMsgType)
                {
                    int msgType = System.Net.IPAddress.NetworkToHostOrder(reader.ReadInt32());//消息类型 160 设备信息
                    if (msgType != PModel.AnswerMsgType)//160,155,156,158
                        return reader;
                }
                //获取公用参数
                _IsSuccse = true;
                return reader;
            }
        }

      最后列举刚刚的通信协议调用部分代码

    /// <summary>
            /// 写入手动控制操作信息  文档2 手动控制,打开关闭设备; 未完成(检查开关状态)
            /// </summary>
            /// <param name="GreenhouseID"></param>
            /// <param name="UserName"></param>
            /// <param name="isDoing">true:打开;false:关闭</param>
            /// <param name="coilStatus"></param>
            public long WriteDevice(int GreenhouseID, string UserName, bool isDoing, long coilStatus)
            {
                GreenHouseDal ghDal = new GreenHouseDal();
                D_GreenhouseInfo ghModel = ghDal.GetModel(new D_GreenhouseInfo() { GreenhouseID = GreenhouseID });//获取终端
                ProtocolModel pModel = new ProtocolModel()
                {
                    UseType = 1,//使用类型,温室
                    IsConServer = ghModel.ConnectType != 1,//是否服务器转发
                    TalkType = (int)GhMsgEnum.TALK,//请求类型
                    AnswerType = (int)GhMsgEnum.TALK,//应答类型
    
                    Sender = string.IsNullOrWhiteSpace(UserName) ? "server" : UserName,//发送者
                    Receiver = (ghModel.ConnectType != 1) ? ghModel.DisplayNo : "dev0",//接收者,网关编号
                    MsgType = isDoing ? (int)GhMsgEnum.SWITCHCTLON : (int)GhMsgEnum.SWITCHCTLOFF,//消息类型为  512、打开开关;513、关闭开关
                    AnswerMsgType = (int)GhMsgEnum.OutputCoil,//应答类型
    
                    //DisplayIP ="192.168.101.31",// (ghModel.ConnectType != 1) ? _DisplayIP : ghModel.DisplayIP,//目标IP
                    //DisplayPort =8085// (ghModel.ConnectType != 1) ? _DisplayPort : (int)ghModel.DisplayPort,//目标端口
    
                    DisplayIP = (ghModel.ConnectType != 1) ? _DisplayIP : ghModel.DisplayIP,//目标IP
                    DisplayPort = (ghModel.ConnectType != 1) ? _DisplayPort : (int)ghModel.DisplayPort,//目标端口
                };
    
                StaticUdpDal bud = new StaticUdpDal();
                MemoryStream stream = bud.GetBaseContent(pModel);//获取基础发送内容
    
                BinaryWriter writer = new BinaryWriter(stream);
                writer.Write(System.Net.IPAddress.HostToNetworkOrder((long)coilStatus));//写入消息内容
    
                writer.Seek(0, SeekOrigin.Begin);
                writer.Write(System.Net.IPAddress.HostToNetworkOrder((short)(stream.Length - 2)));//写入长度
                bud.SendStream = stream;
                bud.LoopNum = 1;
    
                BinaryReader reader = bud.UdpMain();//开始发送和接收
                if (reader == null || !bud.IsSuccse) return (long)-1;//---------------------------------?
    
                long OutputStatus = System.Net.IPAddress.NetworkToHostOrder(reader.ReadInt64());
                return OutputStatus;
            }

    百度上有很多讲 socket通信的,都比较基础,我也是看着别人的代码总结到自己的项目中的,这里有个关键点就是声明一个静态的socket变量,并且使用之后并不关闭,而是常驻内存,收到信号就开启就收线程,然后再将信号转发给服务器。之前做的都是socket使用后立马关闭连接,反而会导致服务器内存使用居高不下。

  • 相关阅读:
    hdu 2896 AC自动机模版题
    快递公司送货员送到货时,打电话通知客户来取的改进
    Scala数据类型中的Symbol(符号文本)
    hdu 3065 AC自动机模版题
    Oracle DB 复制数据库
    Java打包生成exe(使用exe4j和inno setup)
    C#的Lambda表达式嵌套例子
    WPF设置控件获得焦点FocusManager
    Winform给TextBox设置默认值(获取焦点后默认值消失)
    使用signtool.exe来验证程序的数字签名是否成功(命令行)
  • 原文地址:https://www.cnblogs.com/bamboo-zhang/p/10318347.html
Copyright © 2011-2022 走看看