VB.NET关于Socket分包发送的原理分析

本文针对Socket编程中的在线更新场景,详细介绍了如何通过合理设置缓冲区大小、数据分割及设计数据包协议来解决大文件传输的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

关于Socket编程,我之前一直处于小数据传输的阶段,就像什么多人聊天之类的,这几天项目碰到了要做在线更新,就想着肯定要静静的写一个非文字信息传输的Socket程序

 

难点在于:

1、Socket编程中,发送数据和接受数据都需要声明一个缓冲区来存放数据,这个缓冲区的大小设置有讲究,大了可以提高数据传输效率,但是会增加丢包、粘包等现象,小了数据传输效率低,速度减慢并且程序计算量增大

2、一个大的文件不可能直接声明和他大小一样的缓冲区,必须要分包发送,这样字节数据的分割有讲究,最少效率不能拖后腿,影响全局传输速度

3、对于一个大的数据来说,分割成小的数据包后,对于服务器或者客户端来说都是零散的数据,并不知道当前传来的包是干嘛的,这时候每个数据包里应该都设计好数据协议,用来保证每个包正确的完成他的功能

 

首先解决第一个问题

缓冲区大小的设定,在我的程序里我是根据TCP协议(毕竟我的通信协议是TCP)的数据包大小来设定的,虽然不知道这样会不会对传输速度有实质性的改变,但总比猜出一个数字来要好一点,TCP数据包的最大容量是1492 - IP(20) - TCP(20) = 1452(BYTES),我的代码里减掉两个字节当做后面提到的协议位,剩下1450B来当数据位,这样程序的头就出来了(当然我这里直接封装成类了)

[vb]  view plain  copy
 print ?
  1. Dim Sockets As Socket  
  2. '用来存储要发送的数据包的大小,不包含指令位,TCP协议数据包的Data区域大小为1452  
  3. Dim _DataLength As Integer = 1450  
  4.   
  5. '--------------------------------协议--------------------------------  
  6. '所有数据按照DataLength的长度来分割,第一位和第二位为指令位  
  7. '第一位表明这个包的状态,具体说明在PackageState枚举内  
  8. '第二位表明这个包作用,具体说明在PackageAction枚举内  
  9. '--------------------------------------------------------------------  
  10.   
  11. ''' <summary>  
  12. ''' 构造函数  
  13. ''' </summary>  
  14. ''' <param name="S">传入一个Socket对象,用来接受和发送数据</param>  
  15. ''' <remarks></remarks>  
  16. Public Sub New(ByVal S As Socket)  
  17.     Sockets = S  
  18. End Sub  
  19.   
  20. ''' <summary>  
  21. ''' 构造函数  
  22. ''' </summary>  
  23. ''' <remarks></remarks>  
  24. Public Sub New()  
  25.   
  26. End Sub  

 

之后再来解决第二个问题,关于字节数据的分割,看上面的代码我们知道每个包已经定为1450B,也就是说当传入一个数据时,要根据这个数为单位分割成多个小数据包(比如10M的文件,就会分成7232个包,最后一个包肯定不是满的),这里直接上代码,原本以为用For还是会影响效率,但运行起来还是挺不错的,For循环里用Array类去操作字节数组保证了效率

[vb]  view plain  copy
 print ?
  1. ''' <summary>  
  2. ''' 分割字节数组,将一个长的字节数组分成指定元素长度的数组集合  
  3. ''' </summary>  
  4. ''' <param name="data">源字节数组</param>  
  5. ''' <returns></returns>  
  6. ''' <remarks></remarks>  
  7. Public Function SplitByteArray(ByVal data As Byte()) As List(Of Byte())  
  8.     Dim list As New List(Of Byte())  
  9.     For i = 0 To data.Length - 1 Step _DataLength  
  10.         Dim tmp() As Byte  
  11.         If data.Length - i < _DataLength Then  
  12.             ReDim tmp(data.Length - i - 1)  
  13.             Array.ConstrainedCopy(data, i, tmp, 0, data.Length - i)  
  14.         Else  
  15.             ReDim tmp(_DataLength - 1)  
  16.             Array.ConstrainedCopy(data, i, tmp, 0, _DataLength)  
  17.         End If  
  18.         list.Add(tmp)  
  19.     Next  
  20.     Return list  
  21. End Function  

 

最后就要解决最难的一个问题了,协议

在我的这个类里,我把协议分成两个字节放在了数据包的前两位,第一位表明这个包的状态,具体说明在PackageState枚举内,第二位表明这个包作用,具体说明在PackageAction枚举内,然后我就直接上枚举,这个枚举可以根据具体使用情况来定制

[vb]  view plain  copy
 print ?
  1. ''' <summary>  
  2. ''' 枚举此数据包的用途  
  3. ''' </summary>  
  4. ''' <remarks></remarks>  
  5. Enum PackageAction  
  6.     下载 = CByte(1)  
  7.     获取所有项目 = CByte(2)  
  8.     获取指定项目 = CByte(3)  
  9.     废包 = CByte(4)  
  10. End Enum  
  11.   
  12. ''' <summary>  
  13. ''' 枚举此数据包的状态  
  14. ''' </summary>  
  15. ''' <remarks></remarks>  
  16. Enum PackageState  
  17.     后续还有包 = CByte(1)  
  18.     后续没有包 = CByte(2)  
  19.     请求下一个包 = CByte(3)  
  20.     心跳包 = CByte(4)  
  21. End Enum  


好了,基本到这里的话Socket分包的核心问题都已经解决了,接下来就是该怎么发怎么收了,这个类的完整代码在下一篇文章发出

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值