先上图

列举一个通信协议

网关发送环境数据

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

网关发送:

包长度+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));//keywriter.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());//keyif (!((!pModel.IsConServer && key == (int)GhMsgEnum.Key) || (pModel.IsConServer && key == (int)GhMsgEnum.Key1)))//987656789  123454321return reader;//-----------------------------------------不同的地方--------------------------------------------------int replyKind = System.Net.IPAddress.NetworkToHostOrder(reader.ReadInt32());//回复的类型 3if (replyKind != PModel.AnswerType)//3return 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,158return 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,//目标IPDisplayPort = (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使用后立马关闭连接,反而会导致服务器内存使用居高不下。

转载于:https://www.cnblogs.com/bamboo-zhang/p/10318347.html

完整的Socket代码相关推荐

  1. (十二) 完整注释的代码摘录

    title: 完整注释的代码摘录 date: 2019/4/23 20:40:00 toc: true --- 完整注释的代码摘录 作者网页 #include <linux/kernel.h&g ...

  2. DL之DNN:利用numpy自定义三层结构+softmax函数建立3层完整神经网络全部代码实现(探究BP神经网络的底层思想)

    DL之DNN:利用numpy自定义三层结构+softmax函数建立3层完整神经网络全部代码实现(探究BP神经网络的底层思想) 目录 输出结果 代码实现 输出结果 代码实现 #DL之NN:利用numpy ...

  3. Android 拖动条(SeekBar)实例 附完整demo项目代码

    Android 拖动条(SeekBar)实例 附完整demo项目代码 1.拖动条的事件 实现SeekBar.OnSeekBarChangeListener接口.需要监听三个事件: 数值改变(onPro ...

  4. 剑指 Offer 34. 二叉树中和为某一值的路径【附完整可运行代码】

    立志用最少的代码做最高效的表达 输入一棵二叉树和一个整数,打印出二叉树中节点值的和为输入整数的所有路径.从树的根节点开始往下一直到叶节点所经过的节点形成一条路径. 示例: 给定如下二叉树,以及目标和 ...

  5. 【三种解法】剑指 Offer 06. 从尾到头打印链表【附完整可运行代码】

    立志用最少的代码做最高效的表达 输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回). 示例 1: 输入:head = [1,3,2] 输出:[2,3,1] 限制: 0 <= 链表 ...

  6. vue 后台返回的文件流进行预览_vue实现下载文件流完整前后端代码

    这篇文章主要为大家详细介绍了vue实现下载文件流完整前后端代码,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 使用Vue时,我们前端如何处理后端返回的文件流 首先后端返 ...

  7. Netty实现的一个异步Socket代码

    本人写的一个使用Netty实现的一个异步Socket代码 package test.core.nio;import com.google.common.util.concurrent.ThreadFa ...

  8. 前后端分离的用户验证原理及Spring Boot + JWT的框架搭建(附完整的框架代码)之二

    本篇承接上一篇,关于Session以及JWT Token参考: 前后端分离的用户验证原理及Spring Boot + JWT的框架搭建(附完整的框架代码)之一 框架整体描述 框架使用Spring Bo ...

  9. 锻炼左右脑协调的摸鱼必备游戏——《Double Snakes》完整C语言代码!

    锻炼左右脑协调的摸鱼必备游戏--<Double Snakes>完整C语言代码! 目录 锻炼左右脑协调的摸鱼必备游戏--<Double Snakes>完整C语言代码! (一)运行 ...

最新文章

  1. SDUTOJ [2801] 并查集模板
  2. Selector#wakeup()
  3. 博客园php教程,PHP仿博客园,个人博客(1)_PHP教程
  4. 检测空指针 静态检测_Parasoft为G3提供专注于安全性和整体软件质量的静态分析解决方案...
  5. Etcd分布式存储系统
  6. error C2146: 语法错误: 缺少“;”(在标识符“CRC”的前面) ...\...\MyMethod.h
  7. 信息学奥赛一本通1364 二叉树遍历
  8. wps2019无法使用粘贴复制快捷键
  9. 根据身份证号码获取身份证信息(省市县、出生日期、性别)
  10. android studio实现ar,在Android Studio上运行EasyAR
  11. 3D引擎优化: 分布式渲染系统能聚沙成塔
  12. 云效研发效能度量体系,如何展示和解读交付效能数据
  13. leaflet快速渲染聚合矢量瓦片(附源码下载)
  14. Python全栈笔记(三)
  15. Apache-DBUtils实现CRUD操作
  16. JS: 如何计算一个月有多少天
  17. 光年:光走一年的距离
  18. mySQL 事物提交成功不等于数据保存成功
  19. 软件系统维护是一项不吸引人的工作_工作流程管理系统六大特点,助您工作更高效...
  20. 腾讯一年投出1100亿:押注了什么?错过了什么?

热门文章

  1. python 制作动画片_cocos2d from python Animation 动画片的实现
  2. jsp连接mysql更新数据库代码_JSP连接MySQL数据库代码
  3. django mysql windows_Django+MySQL配置:Windows+Centos
  4. PHP 必须勾选用户协议,javascript实现用户必须勾选协议实例讲解
  5. R语言向matlab转化,我有一段MATLAB的程序,现在想转换成R语言代码
  6. mysql-------视图
  7. 备份/恢复面临的问题与解决途径
  8. Html状态属性,html一些对象属性的介绍
  9. win10安装vbox没有虚拟网卡_消失的虚拟网卡
  10. C#通用验证类:邮箱,电话,手机,数字,英文,日期,身份证,邮编,网址,IP