上一篇文章分析了分包发送的原理,这里就发上完整的代码,这个类直接复制下来就可以用
具体用法为创建发送接收实例,传入一个已经和服务器连接好的Socket(因为我才不会帮你连接呢),要发送的时候调用Send方法
(注:不可将Send和Recv放入两个线程中,两者只能在一个线程内,因为在Send的过程中,根据数据协议要求,发数据的同时是要接受返回的校验包的,如果同时另一个线程也在Recv那就乱套)
要接受的时候调用Receive方法,返回一个DataInfo结构,结构体也会同时发上来
<Serializable()>
Public Class DateInfo
Dim Flags As 发送接收.PackageAction
Public Property Flag As 发送接收.PackageAction
Get
Return Flags
End Get
Set(ByVal value As 发送接收.PackageAction)
Flags = value
End Set
End Property
Dim Dates(0) As Byte
Public Property BDate() As Byte()
Get
Return Dates
End Get
Set(ByVal value As Byte())
Dates = value
End Set
End Property
End Class
Public Class 发送接收
Dim Sockets As Socket
'用来存储要发送的数据包的大小,不包含指令位,TCP协议数据包的Data区域大小为1452
Dim _DataLength As Integer = 1450
'--------------------------------协议--------------------------------
' 所有数据按照DataLength的长度来分割,第一位和第二位为指令位
' 第一位表明这个包的状态,具体说明在PackageState枚举内
' 第二位表明这个包作用,具体说明在PackageAction枚举内
'--------------------------------------------------------------------
''' <summary>
''' 构造函数
''' </summary>
''' <param name="S">传入一个Socket对象,用来接受和发送数据</param>
''' <remarks></remarks>
Public Sub New(ByVal S As Socket)
Sockets = S
End Sub
''' <summary>
''' 构造函数
''' </summary>
''' <remarks></remarks>
Public Sub New()
End Sub
''' <summary>
''' 设定或获取此实例每次发送的数据包的长度(已经根据TCP协议的数据包规范默认设为最佳大小,在无特殊情况下建议不要更改)
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public Property DataLength As Integer
Get
Return _DataLength
End Get
Set(ByVal value As Integer)
If _DataLength <= 0 Then
Throw New Exception("数据包长度不允许小于等于0")
Return
End If
_DataLength = value
End Set
End Property
''' <summary>
''' 设定或获取此实例中的Socket对象
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public Property Socket As Socket
Get
Return Sockets
End Get
Set(ByVal value As Socket)
If value Is Nothing Then
Throw New Exception("传入了一个未实例化的Socket对象")
Return
End If
Sockets = value
End Set
End Property
''' <summary>
''' 释放这个实例中的Socket所拥有的资源
''' </summary>
''' <remarks></remarks>
Public Sub Remove()
Sockets.Close()
End Sub
''' <summary>
''' 分割字节数组,将一个长的字节数组分成指定元素长度的数组集合
''' </summary>
''' <param name="data">源字节数组</param>
''' <returns></returns>
''' <remarks></remarks>
Public Function SplitByteArray(ByVal data As Byte()) As List(Of Byte())
Dim list As New List(Of Byte())
For i = 0 To data.Length - 1 Step _DataLength
Dim tmp() As Byte
If data.Length - i < _DataLength Then
ReDim tmp(data.Length - i - 1)
Array.ConstrainedCopy(data, i, tmp, 0, data.Length - i)
Else
ReDim tmp(_DataLength - 1)
Array.ConstrainedCopy(data, i, tmp, 0, _DataLength)
End If
list.Add(tmp)
Next
Return list
End Function
''' <summary>
''' 枚举此数据包的用途
''' </summary>
''' <remarks></remarks>
Enum PackageAction
下载 = CByte(1)
获取所有项目 = CByte(2)
获取指定项目 = CByte(3)
废包 = CByte(4)
End Enum
''' <summary>
''' 枚举此数据包的状态
''' </summary>
''' <remarks></remarks>
Enum PackageState
后续还有包 = CByte(1)
后续没有包 = CByte(2)
请求下一个包 = CByte(3)
心跳包 = CByte(4)
End Enum
''' <summary>
''' 发送数据
''' </summary>
''' <param name="data">源数据</param>
''' <param name="Flag">用途</param>
''' <remarks></remarks>
Public Sub Send(ByVal data As Byte(), ByVal Flag As PackageAction)
If Sockets Is Nothing Then
Throw New Exception("实例中所使用的Socket对象可能还未实例化")
Return
End If
Dim currSend(_DataLength + 1) As Byte
If data Is Nothing Then
Sockets.Send(New Byte() {2, Flag})
Else
Dim list As List(Of Byte()) = SplitByteArray(data)
If list.Count = 0 Then
ReDim currSend(1)
currSend(0) = CByte(2)
currSend(1) = Flag
Try
Sockets.Send(currSend)
Catch ex As Exception
Throw ex
End Try
Return
End If
For i = 0 To list.Count - 1
If i = list.Count - 1 Then
ReDim currSend(list(i).Length + 1)
currSend(0) = CByte(2)
currSend(1) = Flag
Array.ConstrainedCopy(list(i), 0, currSend, 2, list(i).Length)
Try
Sockets.Send(currSend)
Catch ex As Exception
Throw ex
End Try
Return
Return
Else
ReDim currSend(_DataLength + 1)
currSend(0) = CByte(1)
currSend(1) = Flag
Array.ConstrainedCopy(list(i), 0, currSend, 2, _DataLength)
End If
Try
Sockets.Send(currSend)
Dim tmp(0) As Byte
Do Until tmp(0) = CByte(3)
Sockets.Receive(tmp)
Loop
Catch ex As Exception
Throw ex
End Try
Return
Next
End If
End Sub
''' <summary>
''' 接受数据
''' </summary>
''' <returns></returns>
''' <remarks></remarks>
Public Function Receive() As Functions.DateInfo
Dim result As New Functions.DateInfo
Dim list As New List(Of Byte)
Sockets.ReceiveTimeout = 2000
While True
Dim b(_DataLength + 1) As Byte
Try
Dim i As Integer = Sockets.Receive(b)
Select Case b(0)
Case PackageState.心跳包
Continue While
Case PackageState.后续还有包
For z = 2 To i - 1
list.Add(b(z))
Next
Case PackageState.后续没有包
result.Flag = [Enum].Parse(GetType(PackageAction), b(1))
Exit While
End Select
Sockets.Send(New Byte() {3})
Catch ex As Exception
result.Flag = PackageAction.废包
Exit While
End Try
End While
result.BDate = list.ToArray
Return result
End Function
''' <summary>
''' 销毁资源
''' </summary>
''' <remarks></remarks>
Public Sub Close()
MyBase.Finalize()
End Sub
End Class