完整的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 = , 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代码的更多相关文章
- html是什么?一个完整的html代码告诉你(完整实例版)
		html什么意思?这篇文章主要为大家仔细的解释了HTML文档的一个基础的完整代码,还有具体的实例解释,让大家能一下就看懂HTML的基础结构和用法.下面我们一起来看看吧一.html是什么?点击查看htm ... 
- Netty实现的一个异步Socket代码
		本人写的一个使用Netty实现的一个异步Socket代码 package test.core.nio; import com.google.common.util.concurrent.ThreadF ... 
- AVL平衡二叉树实现,图解分析,C++描述,完整可执行代码
		body, table{font-family: 微软雅黑; font-size: 13.5pt} table{border-collapse: collapse; border: solid gra ... 
- SSL握手通信详解及linux下c/c++ SSL Socket代码举例
		SSL握手通信详解及linux下c/c++ SSL Socket代码举例 摘自:http://www.169it.com/article/3215130236.html 分享到:8 发布时 ... 
- SSL握手通信详解及linux下c/c++ SSL Socket代码举例(另附SSL双向认证客户端代码)
		SSL握手通信详解及linux下c/c++ SSL Socket代码举例(另附SSL双向认证客户端代码) 摘自: https://blog.csdn.net/sjin_1314/article/det ... 
- 网络编程之Socket代码实例
		网络编程之Socket代码实例 一.基本Socket例子 Server端: # Echo server program import socket HOST = '' # Symbolic name ... 
- 看完让你彻底理解 WebSocket 原理,附完整的实战代码(包含前端和后端)
		1.前言 最近有同学问我有没有做过在线咨询功能.同时,公司也刚好让我接手一个 IM 项目.所以今天抽时间记录一下最近学习的内容.本文主要剖析了 WebSocket 的原理,以及附上一个完整的聊天室实战 ... 
- socket 代码实例
		 1. TCP SOCKET 客户端: #!/usr/bin/env python # -*-coding:utf-8 -*- import socket HOST = 'localhost' PO ... 
- C#完整的通信代码(点对点,点对多,同步,异步,UDP,TCP)
		C# code namespace UDPServer { class Program { static void Main(string[] args) { int recv; byte[] dat ... 
随机推荐
- 【转帖】联芸Maxio展示国产PCIe SSD主控:速度可达3.5GB/s
			联芸Maxio展示国产PCIe SSD主控:速度可达3.5GB/s https://www.cnbeta.com/articles/tech/855223.htm 国产主控 紫光做国产颗粒 国产器件对 ... 
- Luogu P2572 序列操作
			(是道线段树好题√) 题目链接 题外话:这道题我也不知道卡了自己多少天,从初赛之前就开始做,一直到现在才a掉(时间跨度得有将近十天了吧?) 线段树,嗯,好像很简单的样子. 但事实上因为自己太菜了,卡了 ... 
- zookeeper 选举leader详解
			一.前言 前面学习了Zookeeper服务端的相关细节,其中对于集群启动而言,很重要的一部分就是Leader选举,接着就开始深入学习Leader选举. 二.Leader选举 2.1 Leader选举概 ... 
- WebGPU学习(八):学习“texturedCube”示例
			大家好,本文学习Chrome->webgpu-samplers->texturedCube示例. 上一篇博文: WebGPU学习(七):学习"twoCubes"和&qu ... 
- luogu P2481 [SDOI2010]代码拍卖会
			luogu 题目中的那个大数一定是若干个1+若干个2+若干个3...+若干个9组成的,显然可以转化成9个\(\underbrace {111...1}_{a_i个1}(0\le a_1\le a_2\ ... 
- CTP报单参数详解
			交易所代码 产品类型 业务类型 价格类型 指令类型 价格类型 OrderPriceType 有效期类型 TimeCondition 成交量类型 VolumeCondition 备注 CZCE 郑商所 ... 
- mysql 函数GROUP_CONCAT(temp.amount SEPARATOR ',')的用法
			mysql 函数GROUP_CONCAT(temp.amount SEPARATOR ',')的用法 使用场景:例如:想要查询用户的最喜欢购买的几种商品,这个时候就需要使用group_concat(字 ... 
- Git小结---So far.......
			基本的: 1. 在配置了SSH Key的情况下,clone项目时使用:git clone git@github.com/用户名/仓库名.git 使用这种方式而不使用https的方式的好处在于,在pu ... 
- vue与angular 区别
			1.vue的双向数据绑定是基于 Es5中的getter和setter来实现的,而angular而是由自己实现的一套模板编译规则,需要进行 ‘脏’ 检查,vue则不需要,因此,vue性能上更高一些,但是 ... 
- Win7安装Visual Studio 2019闪退问题
			最近在Win7 系统上安装最新版的VS2019发现 每次在这个画面之后就闪退了,即便换了台电脑也是一样的情况,于是我意识到,这应该是系统本身的问题 经过调查发现是只需要安装两个更新就可以了 这两个更新 ... 
