VB.NET关于Socket分包发送的源码

上一篇文章分析了分包发送的原理,这里就发上完整的代码,这个类直接复制下来就可以用

具体用法为创建发送接收实例,传入一个已经和服务器连接好的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


 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值