C# TCPclient 服务器保持长连接的一种办法(变相的心跳包功能)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace ALARMIP
{
public partial class Form1 : Form
{
//客户端定时向服务器发送查询指令
//服务器内置时钟计数,收到查询指令清零,计数超过则跳出循环,重新产生线程,线程内运行阻塞等待新的连接
//这样如果客户端连接一次就可以持续查询服务器设备,如果出现网络异常或者链接中断,只需客户端重新建立连接
//这个实例的好处是避免采用异步方法造成的非阻塞连接(要求客户端也用非阻塞方式,很多第三方工具无法调试)
byte[] pollingCommand = new byte[12] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 0x04, 0x00, 0x01, 0x00, 0x30 };
// 客户端轮询指令,事务处理标识2字节,协议标识2字节,长度标识2字节,单元标识00,功能标识0A,起始处理器号,总处理器数
//00 00 00 00 00 06 01 04 00 01 00 30
byte[] infoTCP = new byte[57] {0x00, 0x00, 0x00, 0x00, 0x00, 0x33,0x61, 0x04, 0x30,
0x00,0x00,0x00, //0
0x00,0x00,0x00 , //pm1
0x00,0x00,0x00, //2
0x00,0x00,0x00, //3
0x00,0x00,0x00, //4
0x00,0x00,0x00, //5
0x00,0x00,0x00, //6
0x00,0x00,0x00, //7
0x00,0x00,0x00, //8
0x00,0x00,0x00, //9
0x00,0x00,0x00, //10
0x00,0x00,0x00, //11
0x00,0x00,0x00, //12
0x00,0x00,0x00, //13
0x00,0x00,0x00, //14
0x00,0x00,0x00 //15
};
bool isAlarmIPReady = true ; //服务器数据汇总是否完成,由时钟确定,默认500ms,接收到轮询指令且该值为1时答复,否则不做应答;应答后修改为0
bool isPolling=true ; //是否收到轮询指令
private bool isListening; //控制连接传输循环
private TcpListener listener;
private Thread aThread;
private bool isTcpConnected; //存在连接线程的标志,控制线程
private int pollingLost; //无客户端查询次数,网络断开也可用,定时器自动加1,通讯成功则清零
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
timer1.Start();
Thread.Sleep(500);
listener = new TcpListener(IPAddress.Any, 502); //新建socket,允许局域网所有终端访问
listener.Start();
aThread = new Thread(Queue1Thread); //连接线程
isTcpConnected = true; //连接状态标志
aThread.Start();
}
private void timer1_Tick(object sender, EventArgs e)
{
isAlarmIPReady = true; //每500ms标志一次
if(!isListening)
{
if (!isTcpConnected)
{
aThread = new Thread(Queue1Thread);
isTcpConnected = true; //立即标识启动连接,避免开多个线程
aThread.Start();
}
}
else
{
if(++pollingLost>10)
{
pollingLost = 10;// 简易的心跳包,根据
isListening = false; //让TCP线程跳出循环
}
}
}
private void Queue1Thread(object state)
{
TcpClient client = new TcpClient();
client = listener.AcceptTcpClient(); //阻塞,等待新的连接
isListening = true; //该值应该在子线程赋值,如果在主线程,有可能是上一个线程的值false,直接跳出下面的循环而断开连接
pollingLost = 0; //同上
while (isListening)
{
if (client != null)
{
NetworkStream stream = client.GetStream(); //这个对象有系统回收
byte[] buffer = new byte[256];
int ki = client.ReceiveBufferSize;
this.Invoke((EventHandler)(delegate
{
//this.Text = ki.ToString()+DateTime.Now .ToLongTimeString();
}));
stream.Read(buffer, 0, 256);
if (ki > 11)
{
isPolling = true;
for (int i = 2; i < 11; i++)
{
if (pollingCommand[i] != buffer[i])
{
isPolling = false; //对客户端请求验证,避免错码
}
}
if (isAlarmIPReady & isPolling)
{
isAlarmIPReady = false;
pollingLost = 0; //连接失败数清零
infoTCP[0] = buffer[0];
infoTCP[1] = buffer[1];
stream.Write(infoTCP, 0, 57);
// MessageBox.Show(infoTCP [5].ToString());
}
}
}
}
client.Close(); //加此处理,则5秒超时后,客户端不重连而发送查询后连接将关闭;如果不做处理,系统将自动回收,客户端不重连发送查询后连接显示保持但是实际上已经断开了连接
isTcpConnected = false;
}
}
}
- SQL SERVER 内存分配及常见内存问题 DMV查询
- 6 利用Docker .NET应用程序模板制作您的容器应用程序(第2部分)
- Mesos+Zookeeper+Marathon的Docker管理平台部署记录(1)
- git review报错一例
- Nginx采用https加密访问后出现的问题
- 对比git rm和rm的使用区别
- Gerrit日常操作命令收集
- 轻型的ORM类Dapper
- [原创]Gerrit中文乱码问题解决方案分享
- 获奖案例:国航&百度“微笑启航”AI主题航班
- MySQL高可用架构-MMM环境部署记录
- Silverlight之ListBox/Style学习笔记--ListBox版的图片轮换广告
- MySQL高可用架构-MHA环境部署记录
- 分布式监控系统Zabbix-3.0.3-完整安装记录 - 添加shell脚本监控
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Koa - 初体验(写个接口)
- Koa - 中间件(理解中间件、实现一个验证token中间件)
- Koa - 使用koa-multer上传文件(上传限制、错误处理)
- 原生js 复制内容到剪切板
- Vue - watch高阶用法
- 小程序如何支持使用 async/await (构建npm版)
- require.context批量引入文件
- Node笔记 - process.cwd() 和 __dirname 的区别
- 小程序如何支持使用 async/await
- 小程序 - 如何自定义导航栏
- protobuf 语法 与 protocol-buffers 的使用
- 小程序 - 简单实现mixin功能
- 记录一些小技巧-CSS篇
- 记录一些小技巧-JS篇
- 初次在Vue项目使用TypeScript,需要做什么