先上图

列举一个通信协议

网关发送环境数据

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

网关发送:

包长度+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 = , recNum;
private int _LoopNum = ;//循环计数器和循环等待次数
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) ? : 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();//时间间隔为1秒
} } /// <summary>
/// 接收发送给本机ip对应端口号的数据报
/// </summary>
public BinaryReader ReciveMsg()
{
byte[] data = new byte[]; while (true)
{
recNum++;
if (recNum > || !IsRun) // 3秒未接收到消息,或标记变为停止,停止
{
IsRun = false;
return null;
} if (socket == null || socket.Available < )
{ Thread.Sleep(); 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(); 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)));//长度
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 * ));//发送者
writer.Write(Encoding.BigEndianUnicode.GetBytes(pModel.Sender)); writer.Write(System.Net.IPAddress.HostToNetworkOrder((int)pModel.Receiver.Length * ));//接收者
writer.Write(Encoding.BigEndianUnicode.GetBytes(pModel.Receiver)); writer.Write(System.Net.IPAddress.HostToNetworkOrder((int)pModel.MsgType));//消息类型
if (pModel.UseType == )
{
writer.Write(System.Net.IPAddress.HostToNetworkOrder((int)pModel.DisplayNo.Length * )); //终端编号 日光温室
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)//
return reader;
int senderLen = System.Net.IPAddress.NetworkToHostOrder(reader.ReadInt32());//发送者的长度
byte[] temp = new byte[];
temp = reader.ReadBytes(senderLen);
string No = Encoding.BigEndianUnicode.GetString(temp); int receiveLen = System.Net.IPAddress.NetworkToHostOrder(reader.ReadInt32());//接收者的长度
string receive;
if (receiveLen > )
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 = ,//使用类型,温室
IsConServer = ghModel.ConnectType != ,//是否服务器转发
TalkType = (int)GhMsgEnum.TALK,//请求类型
AnswerType = (int)GhMsgEnum.TALK,//应答类型 Sender = string.IsNullOrWhiteSpace(UserName) ? "server" : UserName,//发送者
Receiver = (ghModel.ConnectType != ) ? 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 != ) ? _DisplayIP : ghModel.DisplayIP,//目标IP
DisplayPort = (ghModel.ConnectType != ) ? _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(, SeekOrigin.Begin);
writer.Write(System.Net.IPAddress.HostToNetworkOrder((short)(stream.Length - )));//写入长度
bud.SendStream = stream;
bud.LoopNum = ; BinaryReader reader = bud.UdpMain();//开始发送和接收
if (reader == null || !bud.IsSuccse) return (long)-;//---------------------------------? long OutputStatus = System.Net.IPAddress.NetworkToHostOrder(reader.ReadInt64());
return OutputStatus;
}

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

完整的Socket代码的更多相关文章

  1. html是什么?一个完整的html代码告诉你(完整实例版)

    html什么意思?这篇文章主要为大家仔细的解释了HTML文档的一个基础的完整代码,还有具体的实例解释,让大家能一下就看懂HTML的基础结构和用法.下面我们一起来看看吧一.html是什么?点击查看htm ...

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

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

  3. AVL平衡二叉树实现,图解分析,C++描述,完整可执行代码

    body, table{font-family: 微软雅黑; font-size: 13.5pt} table{border-collapse: collapse; border: solid gra ...

  4. SSL握手通信详解及linux下c/c++ SSL Socket代码举例

    SSL握手通信详解及linux下c/c++ SSL Socket代码举例 摘自:http://www.169it.com/article/3215130236.html   分享到:8     发布时 ...

  5. SSL握手通信详解及linux下c/c++ SSL Socket代码举例(另附SSL双向认证客户端代码)

    SSL握手通信详解及linux下c/c++ SSL Socket代码举例(另附SSL双向认证客户端代码) 摘自: https://blog.csdn.net/sjin_1314/article/det ...

  6. 网络编程之Socket代码实例

    网络编程之Socket代码实例 一.基本Socket例子 Server端: # Echo server program import socket HOST = '' # Symbolic name ...

  7. 看完让你彻底理解 WebSocket 原理,附完整的实战代码(包含前端和后端)

    1.前言 最近有同学问我有没有做过在线咨询功能.同时,公司也刚好让我接手一个 IM 项目.所以今天抽时间记录一下最近学习的内容.本文主要剖析了 WebSocket 的原理,以及附上一个完整的聊天室实战 ...

  8. socket 代码实例

    ​ 1. TCP SOCKET 客户端: #!/usr/bin/env python # -*-coding:utf-8 -*- import socket HOST = 'localhost' PO ...

  9. C#完整的通信代码(点对点,点对多,同步,异步,UDP,TCP)

    C# code namespace UDPServer { class Program { static void Main(string[] args) { int recv; byte[] dat ...

随机推荐

  1. 浅析射线检测 raycast 的使用 !Cocos Creator 3D !

    哎呀?为什么我设置了节点点击回调没反应呀? 记得在写小鸡拍拍的时候遇到一个问题,想要捕捉排球的点击事件,按照 2d 的写法,给3d 节点添加 node 事件,结果点了没反应.代码大概是以下的样子. t ...

  2. poj1061(扩展欧基里德定理)

    题目链接:https://vjudge.net/problem/POJ-1061 题意:在一个首位相接的坐标轴上,A.B开始时分别位于X,Y处,每个单位时间向右移动m,n米,问是否能相遇,坐标轴长L. ...

  3. Maven - Maven3实战学习笔记(2)坐标和依赖

    1.maven坐标元素 maven坐标元素包括:groupId.artifactId.version.packaging.classifier. classifier:定义输出的附属构件.groupI ...

  4. Nob常用命令

    说明:此文件为常用的命令笔记 规则: .使用"[组名]"分组,如[linux] .使用"<标题一>"标示知识点,可用"<<二级 ...

  5. ubuntu中安装Python3.7

    一. 源码安装: 1. 官网源码下载: Python官网:https://www.python.org/downloads/ setuptools官网:https://pypi.org/project ...

  6. linux查看网络ip得两个命令ifconfig和 ip addr

    在安装linux 得时候,我们要选择桥接网络,相当于本电脑和虚拟机得电话都是接通外网,linux查看网络ip得两个命令ifconfig和 ip addr 1,命令ifconfig 如果ifconfig ...

  7. BZOJ 3189. [Coci2011]Slika

    传送门 有回档操作,考虑离线,这样就知道最终的操作序列了 发现前面的操作会被后面覆盖,干脆直接从后往前操作,如果一个位置以前染色过了那就不用再染色 所以我们可以用 $n$ 个链表维护 $n$ 个行,操 ...

  8. 实现 RSA 算法之改进和优化(第三章)(老物)

    第三章 如何改进和优化RSA算法 这章呢,我想谈谈在实际应用出现的问题和理解. 由于近期要开始各种忙了,所以写完这章后我短时间内也不打算出什么资料了=- =(反正平时就没有出资料的习惯.) 在讲第一章 ...

  9. luogu P3210 [HNOI2010]取石头游戏

    传送门 不会结论做个鬼系列 题意其实是在头尾(最多)两个栈以及中间一些双端队列依次取数,然后每个人都要最大化自己的价值 有一个结论,如果一段序列中,出现了三个相邻位置\(A,B,C\),满足\(A\l ...

  10. TCP的三次握手与四次挥手理解及面试题

    TCP的三次握手与四次挥手理解及面试题(很全面) 转载自:https://blog.csdn.net/qq_38950316/article/details/81087809 本文经过借鉴书籍资料.他 ...