使用“带外数据”实现TCP心跳包
2016-03-16 17:19
507 查看
使用“带外数据”实现TCP心跳包
标签: 带外数据网络心跳包2011-11-17 10:17 2398人阅读 评论(2) 收藏 举报
分类:
VB.NET(1)
版权声明:本文为博主原创文章,未经博主允许不得转载。
公司有一个基于TCP的IM项目,开发人员将心跳包与数据流混在了一起,从而增加了数据提取的难度和出错的机率,我提出使用带外数据来实现心跳包,该开发人员认为这是一种过时的不被.NET支持的技术特性,其实.NET不是空中楼阁,他的所有技术都是基于原来WIN32技术的基础之上的,只不过增强了OO特性而已,为验证自己的想法,因此花费了几个小时编写了使用“带外数据”实现TCP心跳包的DEMO类,并成功通过测试。
该DEMO类分别对应SOCKET通讯的SERVER端和CLIENT端进行了不同处理,两端的心跳时间间隔最好设为一致,否则可能导致结果错误,此外,由于心跳包是定时异步执行的,在开发期间如果有暂停运行的调试需要,最好将心跳包功能暂时关闭,以免因心跳包发送或接收超时而抛出错误。
一、心跳包代码如下:
[vb] view
plain copy
'* *************************************************************** *
'* 模块名称:NetHeartbeat.vb
'* 功能描述:心跳包处理类
'* 作者:lyserver
'* 编码日期:2011年11月14日
'* 修改日期:
'* *************************************************************** *
Imports System.Net.Sockets
''' <summary>
''' 心跳包处理类
''' </summary>
Public Class NetHeartbeat
Implements IDisposable
''' <summary>
''' 心跳包处理方式(发送或接收)
''' </summary>
Public Enum MethodConstants
[Send] = 0
[Recv] = 1
End Enum
''' <summary>
''' 心跳包描述类
''' </summary>
Private Class HeartbeatInfo '心跳包信息
Public Buffer As Byte() = New Byte(0) {} '心跳包数据缓冲区
Public Times As Integer = 0 '心跳包检测次数
Public Success As Boolean = True '心跳包发送或接收成功标志
End Class
Private m_Socket As Socket = Nothing '套接字
Private WithEvents m_Timer As Timers.Timer = New Timers.Timer(1000) '定时器
Private m_HeartbeatInfo As HeartbeatInfo = Nothing '心跳包描述对象
Private m_Method As MethodConstants = MethodConstants.Send '心跳包处理方式
Private m_TryTimes As UInteger = 5 '心跳包出错后的最大尝试次数
Public Delegate Sub MyEventHandler(ByVal sender As NetHeartbeat, ByVal message As String)
Public Event OnError As MyEventHandler
Public Sub New()
End Sub
Public Sub New(ByVal sock As Socket)
m_Socket = sock
End Sub
Public Sub New(ByVal sock As Socket, ByVal method As MethodConstants)
m_Socket = sock
m_Method = method
End Sub
Public Sub New(ByVal sock As Socket, ByVal method As MethodConstants, ByVal enabled As Boolean)
m_Socket = sock
m_Method = method
Me.Enabled = enabled
End Sub
Public Sub New(ByVal sock As Socket, ByVal method As MethodConstants, ByVal enabled As Boolean, ByVal interval As Integer)
m_Socket = sock
m_Method = method
Me.Enabled = enabled
Me.Interval = interval
End Sub
''' <summary>
''' 重置心跳包处理状态
''' </summary>
Public Sub Reset()
If m_HeartbeatInfo Is Nothing Then
m_HeartbeatInfo = New HeartbeatInfo()
End If
m_HeartbeatInfo.Times = 0
m_HeartbeatInfo.Success = True
End Sub
''' <summary>
''' 绑定套接字,并指定心跳包处理方式
''' </summary>
Public Sub Bind(ByVal sock As Socket, ByVal method As MethodConstants)
m_Socket = sock
m_Method = method
End Sub
''' <summary>
''' 启动或停止心跳包
''' </summary>
Public Property Enabled() As Boolean
Get
Return m_Timer.Enabled
End Get
Set(ByVal value As Boolean)
Reset()
m_Timer.Enabled = value
End Set
End Property
''' <summary>
''' 心跳包处理间隔时间(毫秒)
''' </summary>
Public Property Interval() As UInteger
Get
Return m_Timer.Interval
End Get
Set(ByVal value As UInteger)
m_Timer.Interval = value
End Set
End Property
''' <summary>
''' 心跳包接收或发送时出错、超时、失败后重试次数
''' </summary>
Public Property TryTimes() As UInteger
Get
Return m_TryTimes
End Get
Set(ByVal value As UInteger)
m_TryTimes = value
End Set
End Property
''' <summary>
''' 心跳包处理方式:接收或发送
''' </summary>
Public Property Method() As MethodConstants
Get
Return m_Method
End Get
Set(ByVal value As MethodConstants)
m_Method = value
End Set
End Property
''' <summary>
''' 发送心跳包
''' </summary>
Private Sub SendHeartbeat()
Try
If m_HeartbeatInfo.Success = True Then '如果上一次发送动作已成功,则继续发送心跳包
m_HeartbeatInfo.Success = False
m_Socket.BeginSend(m_HeartbeatInfo.Buffer, 0, 1, SocketFlags.OutOfBand, AddressOf Me.EndSendOOB, Nothing)
Else '否则,超时计数器加1
m_TryTimes += 1
End If
Catch ex As Exception
ErrorHandler(ex.Message)
End Try
End Sub
Private Sub EndSendOOB(ByVal ar As IAsyncResult)
Try
Dim nSendCount As Integer = m_Socket.EndSend(ar)
m_HeartbeatInfo.Success = True '设置心跳包发送成功标志
m_TryTimes = 0 '超时计数器归0
Catch ex As Exception
ErrorHandler(ex.Message)
End Try
End Sub
''' <summary>
''' 接收心跳包
''' </summary>
Private Sub RecvHeartbeat()
Try
If m_HeartbeatInfo.Success = True Then '如果上一次接收动作已成功,则继续接收心跳包
m_HeartbeatInfo.Success = False
m_Socket.BeginReceive(m_HeartbeatInfo.Buffer, 0, 1, SocketFlags.OutOfBand, AddressOf Me.EndRecvOOB, Nothing)
Else '否则,超时计数器加1
m_TryTimes += 1
End If
Catch ex As Exception
ErrorHandler(ex.Message)
End Try
End Sub
Private Sub EndRecvOOB(ByVal ar As IAsyncResult)
Try
Dim nRecvCount As Integer = m_Socket.EndReceive(ar)
m_HeartbeatInfo.Success = True '设置心跳包接收成功标志
m_TryTimes = 0 '超时计数器归0
Catch ex As Exception
ErrorHandler(ex.Message)
End Try
End Sub
''' <summary>
''' 定时检查心跳包发送或接收情况,并根据结果判断是否继续发送或接收心跳包,或者抛出心跳包处理异常
''' </summary>
Private Sub m_Timer_Elapsed(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles m_Timer.Elapsed
If m_HeartbeatInfo Is Nothing Then
m_Timer.Enabled = False
Exit Sub
End If
Try
If m_Method = MethodConstants.Send Then '如果心跳包处理方式为发送
If m_HeartbeatInfo.Success = True Then '如果心跳包已发送成功,则继续发送
SendHeartbeat()
Console.WriteLine("心跳包发送成功")
Else '否则,心跳包发送超时或出错
If m_HeartbeatInfo.Times < m_TryTimes Then '如果超时或出错次数小于指定的次数,则继续发送
SendHeartbeat()
Else '否则,抛出心跳包发送异常错误
ErrorHandler("心跳包发送超时")
End If
End If
Else '如果心跳包处理方式为接收
If m_HeartbeatInfo.Success = True Then '如果心跳包已接收成功,则继续接收
RecvHeartbeat()
Console.WriteLine("心跳包接收成功")
Else '否则,心跳包接收超时或出错
If m_HeartbeatInfo.Times < m_TryTimes Then '如果超时或出错次数小于指定的次数,则继续接收
RecvHeartbeat()
Else '否则,抛出心跳包接收异常错误
ErrorHandler("心跳包接收超时")
End If
End If
End If
Catch ex As Exception
ErrorHandler(ex.Message)
End Try
End Sub
''' <summary>
''' 异常处理
''' </summary>
Private Sub ErrorHandler(ByVal message As String)
Try
m_Timer.Enabled = False
If m_HeartbeatInfo IsNot Nothing Then
m_HeartbeatInfo.Times = m_TryTimes
m_HeartbeatInfo.Success = False
End If
Catch ex As Exception
End Try
RaiseEvent OnError(Me, message)
End Sub
Private disposedValue As Boolean = False ' 检测冗余的调用
' IDisposable
Protected Overridable Sub Dispose(ByVal disposing As Boolean)
If Not Me.disposedValue Then
If disposing Then
' TODO: 显式调用时释放非托管资源
End If
' TODO: 释放共享的非托管资源
m_Timer.Enabled = False
m_Socket = Nothing
m_HeartbeatInfo = Nothing
End If
Me.disposedValue = True
End Sub
#Region " IDisposable Support "
' Visual Basic 添加此代码是为了正确实现可处置模式。
Public Sub Dispose() Implements IDisposable.Dispose
' 不要更改此代码。请将清理代码放入上面的 Dispose(ByVal disposing As Boolean) 中。
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
#End Region
End Class
二、类使用说明:
1、如果要处理心跳包事件,请使用Private WithEvents m_Heartbeat As NetHeartbeat = New NetHeartbeat 来实例化心跳包。
2、如果要修改心跳包处理方式,请使用Heartbeat .Bind(sock,MethodConstants.Recv)方法来指定心跳包的处理套接字和处理方式,建议最好由客户端发送心跳包,服务器端接收心跳包。
3、如果要修改心跳包处理的时间间隔,请修改m_Heartbeat的Interval属性,该时间间隔的单位为毫秒。
4、如果要启动心跳包,请设置m_Heartbeat的Enabled属性为True。
相关文章推荐
- Tomcat 启用 HTTPS
- 获取网络图片宽高
- BZOJ3931 网络吞吐量(最大流)
- TCP通信中的粘包问题
- 在AppDelegate中检测当前网络状态
- OKHttp介绍和实例展示
- C++ 网络编程:一个可复用的套接字管理类和一个简单用例
- bzoj 1834 [ZJOI2010]network 网络扩容(MCMF)
- HTTP详解
- 基于http live streaming, 使用vlc + mediastreamsegmenter + apache 实现iOS视频直播
- iOS网络3—UIWebView与WKWebView使用详解
- 编写天气Demo,接触OKhttp框架,框架没那么难
- Java网络编程(二)总结
- iOS之网络编程
- HTTP和HTTPS的区别
- keras:保存keras学习好的深度神经网络模型参数为二进制和txt文件
- TCP/UDP网络编程
- 网络编程释疑之:同步,异步,阻塞,非阻塞
- iOS 判断有无网络连接
- C#和java和android中的NetWorkAdapter,httpRequest,WebView,json,xml