完整的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 ...
随机推荐
- 2019JAVA第三次实验报告
Java实验报告 班级 计科二班 学号 20188442 姓名 吴怡君 完成时间 2019.9.24 评分等级 实验三 String类的应用 一.实验目的 掌握类String类的使用: 学会使用JDK ...
- etcd常用命令-增删改查
增删改查key-values 插入数据测试 # etcdctl put name1 james# etcdctl put name11 alice# etcdctl put name12 seli # ...
- webpack的插件 http-webpack-plugin。 webpack-dev-server
自动的生成: bundle.js 和 index.html 在该项目的目录下:npm init -yes npm install vue -D npm install webpack@3.12.0 ...
- emmet语法列表
emmet语法 来源:https://docs.emmet.io/cheat-sheet/ Child: > nav>ul>li <nav> <ul> &l ...
- Cookie、Session和LocalStorage
前记 前面我已经写了一篇关于Cookie的文章,但是那时候我其实理解的并不是很深刻,会有些搞不懂的地方,今天我就再写一次,博客也是我的学习笔记 Cookie Cookie是服务器发送到用户浏览器并保存 ...
- source与./执行的区别
source与./执行的区别作用:使文件生效区别:1.source不需要文件有可执行(x)权限,而./需要文件有x权限,否则报错2.source执行是在当前shell中执行,./在当前shell的子s ...
- java 实现傅立叶变换算法 及复数的运算
最近项目需求,需要把python中的算法移植到java上,其中有一部分需要用到复数的运算和傅立叶变换算法,废话不多说 如下: package qrs; /** * 复数的运算 * */ public ...
- vue-cli设置引入目录
打开build/webpack.base.conf.js 找到module.exports下的resolve这行 刚开始是这样的 resolve: { extensions: ['.js', '.vu ...
- js数组与对象的区别
数组和对象两者都可以用来表示数据的集合,曾一度搞不清楚”数组”(array)和”对象”(object)的根本区别在哪里. 有一个数组a=[1,2,3,4],还有一个对象a={0:1,1:2,2:3,3 ...
- 21个CSS3 / JS 时钟
收集了21个酷炫的CSS / JS实现的时钟效果https://oktools.net/clocks 预览 :https://clocks.oktools.net/0/ 源码 :https://cod ...