Winsock缓冲区大小问题

bodybo 2010-09-28 01:08:50
windsock缓冲区大小默认为8192字节,尝试用API函数setsocketopt修改,似乎也修改成功了,代码如下:

Dim lResult As Long
Dim bufSize As Long
bufSize = CLng(1024) * 1024
lResult = setsockopt(Winsock1.SocketHandle, SOL_SOCKET, SO_RCVBUF, bufSize, 4)
If (lResult = SOCKET_ERROR) Then
MsgBox "Error setting SO_RCVBUF option: " & CStr(Err.LastDllError)
End If
lResult = setsockopt(Winsock1.SocketHandle, SOL_SOCKET, SO_SNDBUF, bufSize, 4)
If (lResult = SOCKET_ERROR) Then
MsgBox "Error setting SO_SNDBUF option: " & CStr(Err.LastDllError)
End If

bufSize = 0
lResult = getsockopt(Winsock1.SocketHandle, SOL_SOCKET, SO_RCVBUF, bufSize, 4)
If (lResult = SOCKET_ERROR) Then
MsgBox "Error getting SO_RCVBUF option: " & CStr(Err.LastDllError)
End If
'bufSize=1024*1024,说明设置成功


发送端是用vc写的程序,也设置了发送缓冲区为1024*1024,可在Winsock1_DataArrival接收大数据包时还是接收到按8192分割的数据包,不知为何?难道对winsock控件缓冲区的修改无效吗?
...全文
515 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
bodybo 2010-10-15
  • 打赏
  • 举报
回复
不好意思,才来结贴。
最后自己定了个分包协议把问题解决了。
测试中发现即使发送比默认的8192字节缓冲区大小还小的数据包,也可能被分包发送,可能跟瞬时网络环境和底层处理有关吧。

谢谢SupermanKing热心回复!
现在还是人类 2010-09-30
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 bodybo 的回复:]
谢谢大家的回复,忙了一天,才过来看到。

提问题时就说了,我发送端的发送缓冲区也改成了1024*1024,可还是不行。可能和supermanking所说的底层硬件有关。看来只有自定协议组包了。
[/Quote]
估计你是想达到对方发一个完整数据你这边直接收一次就处理了吧。
但这个思路有些问题,就是没有稳定性,特别对较大的数据而言肯定会失败。
所以你还是要加强应用层通讯协议的定制,如果考虑再周全点,还可以考虑数据校验等方法
再验证数据传输的正确性。
如果你对应用层通讯协议不理解,建议参考一下FTP协议或POP3协议等现成的应用层协议。
了解了别人的处理方法后自己再来做你的处理过程肯定会有一定的进步。至于数据完整性的
验证,通常来说在应用层不用做得很多,甚至很多都没有。但就 VB 里的 Winsock 控件来说,
在 Internet 上大面积运用,还是会有传输数据有问题的时候,这个我已经领教过了,当然
不是每一次都会出现问题,但是会时不时出现问题,而且不是自己的问题,是控件本身的
问题,这才叫人抓狂。所以有时候数据正确性的校验也是有必要的。可以采用CRC16、CRC32
也可以采用简单点的异或校检法等,大致的处理一下,数据传输稳定性会强很多。
苍狼传说 2010-09-29
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 supermanking 的回复:]
DataArrival事件的触发和缓冲区大小无关,因为他的触发过程是和网络协议包的时间有关。
网络接收是这样的,在一定时间(比如500us)内继续收到相对应的数据包,他会将收到的数
据包数据连续的填入缓冲区,但是超出一定时间(比如500us),再异步通讯中他就会触发
FD_READ 消息产生 DataArrival 事件。除非是连续的包太多,他才会根据缓冲区大小来
产生 DataArri……
[/Quote]
受教了
因为楼主在VB中开发的话,主要使用MSWinsock.ocx组件,微软封装过的一些特性,只要数据提取及,因此不会出现几包数据一起收到或者需要自己拼包的情况。
但在底层自己做协议,另当别论
现在还是人类 2010-09-29
  • 打赏
  • 举报
回复
这是我在VB中写的Sock类的一个Send方法,你看看过程就知道什么回事了,
在硬件层的交换,把整个数据还要再分包,那就是正真的网络数据包了。

'==============================================================================
'类方法定义及处理过程
'==============================================================================
'********************************************************************************
'** 方 法 名 : SendData
'** 输 入 : data(Variant) - 要通过Sock发送的任何类型数据内容
'** 返 回 : 无
'** 功能描述 : 发送网络数据
'********************************************************************************
Public Sub SendData(data As Variant)
Dim SendBuffers() As Byte
Dim SendBuffersSize As Long
Dim CancelERR As Boolean
Dim DataSize As Long
Dim SockSendCount As Long
Dim SockSendBuffers() As Byte
Dim rd As Long
'将要发送的数据进行字节流格式化
Select Case VarType(data)
Case vbString: SendBuffers = StrConv(data, vbFromUnicode)

Case vbArray + vbByte:
SendBuffers = data
End Select
SendBuffersSize = UBound(SendBuffers) + 1
'取得发送缓冲区大小
rd = api_getsockopt(mvarSocketHandle, _
SOL_SOCKET, _
SO_SNDBUF, _
DataSize, _
4)
If rd = SOCKET_ERROR Then
CancelERR = False
RaiseEvent SockError(35756, _
"不能完成请求。", _
0, _
"WinSock.SendData.getsockopt", _
"", _
0, _
CancelERR)
If CancelERR = False Then
Err.Raise vbObjectError + 35756, "不能完成请求。", 35756, "", 0
End If
Exit Sub
End If

'发送TCP数据
SendMaxSize = DataSize
SendNowSize = 0
If SendBuffersSize <= DataSize Then
'发送的内容小于或等于Sock发送缓冲区的大小,所以进行一次性发送数据
rd = api_send(mvarSocketHandle, SendBuffers(0), SendBuffersSize, 0&)
If rd = SOCKET_ERROR Then
mvarState = sckError
CancelERR = False
RaiseEvent SockError(35756, _
"不能完成请求。", _
0, _
"WinSock.SendData.send", _
"", _
0, _
CancelERR)
If CancelERR = False Then
Err.Raise vbObjectError + 35756, "不能完成请求。", 35756, "", 0
End If
Exit Sub
End If
RaiseEvent SendComplete
Else
'自动分包发送数据
SockSendCount = 0
SendMaxSize = SendBuffersSize
ReDim SockSendBuffers(DataSize - 1)
Do
CopyMemory SockSendBuffers(0), SendBuffers(SockSendCount), DataSize
AfreshSendData:
rd = api_send(mvarSocketHandle, SockSendBuffers(0), DataSize, 0&)
If rd = SOCKET_ERROR Then
'出错重发
GoTo AfreshSendData
ElseIf rd = DataSize Then
'发送成功
Else
mvarState = sckError
CancelERR = False
RaiseEvent SockError(35756, _
"不能完成请求。", _
0, _
"WinSock.SendData.send", _
"", _
0, _
CancelERR)
If CancelERR = False Then
Err.Raise vbObjectError + 35756, "不能完成请求。", 35756, "", 0
End If
Exit Sub
End If
SockSendCount = SockSendCount + DataSize
SendNowSize = SockSendCount

'RaiseEvent SendProgress(SendNowSize, SendBuffersSize)
If SockSendCount >= SendBuffersSize Then
DataSize = 0
Else
If SockSendCount + DataSize >= SendBuffersSize Then
DataSize = (SendBuffersSize - SockSendCount)
End If
End If
Loop While DataSize > 0
RaiseEvent SendComplete
End If

End Sub
现在还是人类 2010-09-29
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 wolfcapita 的回复:]
只修改了自己的缓冲区,别人发过来的包你是改不了的举个例子:
两个Socket缓冲区是仓库,你把自己的仓库改为1024*1024这么大了,别人给你的包裹是8192一个包,难道你想要求人家把8192的包拆开再组合吗?那就不是原来的包了
[/Quote]
别以为发送端改了缓冲区大小就可以,因为到了底层,还是将数据分成一个一个很小的网络数据包发送的,
因为在硬件层,比如交换机,不可能有那么大的 RAM 来交换那么大量的数据,所以最终还是通过数据交换
协议将数据分割成一个一个很小的数据包在硬件层传输,而且还因为硬件层处理的不只是一个事务,所以
还将这些包按任务队列来分发,在多个小任务交叉执行的时候,看上去好像每个点都能正常同时传输一样,
但是在队列中,如果因为其他的网络信息也需要传输并把任务插入队列,就有可能影响到原来队列中的任务
执行情况,所以对于连续数据包超时产生 FD_READ 消息的时间所包含的已接受缓冲区数量也未必全部相同,
特别是在 Internet 的网络环境中这个问题就特别体现得严重。
现在还是人类 2010-09-29
  • 打赏
  • 举报
回复
DataArrival事件的触发和缓冲区大小无关,因为他的触发过程是和网络协议包的时间有关。
网络接收是这样的,在一定时间(比如500us)内继续收到相对应的数据包,他会将收到的数
据包数据连续的填入缓冲区,但是超出一定时间(比如500us),再异步通讯中他就会触发
FD_READ 消息产生 DataArrival 事件。除非是连续的包太多,他才会根据缓冲区大小来
产生 DataArrival,但通常情况下,不会有那么好的网络条件在路由或交换队列中全是你一
个人的连续作业包。
苍狼传说 2010-09-29
  • 打赏
  • 举报
回复
改了自己的缓冲区,只能够说自己这边一次性能够接收1024*1024这么大的包而己。
苍狼传说 2010-09-29
  • 打赏
  • 举报
回复
只修改了自己的缓冲区,别人发过来的包你是改不了的举个例子:
两个Socket缓冲区是仓库,你把自己的仓库改为1024*1024这么大了,别人给你的包裹是8192一个包,难道你想要求人家把8192的包拆开再组合吗?那就不是原来的包了
bodybo 2010-09-29
  • 打赏
  • 举报
回复
没人知道吗?
bodybo 2010-09-29
  • 打赏
  • 举报
回复
谢谢大家的回复,忙了一天,才过来看到。

提问题时就说了,我发送端的发送缓冲区也改成了1024*1024,可还是不行。可能和supermanking所说的底层硬件有关。看来只有自定协议组包了。

7,762

社区成员

发帖
与我相关
我的任务
社区描述
VB 基础类
社区管理员
  • VB基础类社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧