在收到所有数据之前,Socket.Receive不会阻塞

时间:2013-04-18 13:10:07

标签: .net vb.net sockets

艾!

我试图获取一个ftp文件列表,并且已经有一个小型库可以做到这一点。事情是Socket.Receive()函数在收到所有数据之前不会阻塞。当我在该行设置断点时,它会收到所有数据,但如果我不这样做,那么只有38个字节(应该是380左右)。

以下是代码:

While True
    Dim bytes As Integer = cSocket.Receive(buffer, buffer.Length, SocketFlags.None)
    mes += ASCII.GetString(buffer, 0, bytes)
    If bytes < buffer.Length Then
        Exit While
    End If
End While

正如我所说:如果断点设置在带有.Receive部分的行中,它就可以工作。我可以使用一种解决方法来保证一个额外的循环,但这似乎非常脏。有什么想法吗?

//编辑:所以让我添加更多信息。我不知道会收到多少数据。代码来自从ftp服务器接收数据的函数。我认为当消息以CRLF结束时我可以停止,但我不能这样做,因为列出的每个文件之间都有一个CRLF。例: file1.textCRLFfile2.txtCLRFfile3.txtCRLF

有时当我打电话给它时,即使有更多的文件要列出,它也只会在最后返回一个带有CRLF的文件。所以这种情况对我来说似乎不稳定。

1 个答案:

答案 0 :(得分:4)

在这种情况下,您对“所有数据”究竟是什么意思?在套接字关闭之前,总会有更多数据。网络堆栈不知道或不关心某些数据在逻辑上属于一起。它会被切换成不同大小的IP数据包(由complex algorithms确定)。

对于您作为接收方,这意味着您将以块的形式获取正在接收的数据。您需要继续致电Receive,直到您知道自己拥有所需的所有数据为止。

来自MSDN documentation(强调我的):

  

如果您使用面向连接的Socket,Receive方法将会   读取尽可能多的数据, 直到 指定的字节数   通过尺寸参数。

在设置断点时看到不同行为的原因是因为您在发送方发送数据时实际上暂停了应用程序。操作系统仍将接收数据包并缓冲它们,直至某一点。标准缓冲区大小为8192字节,可以使用ReceiveBufferSize属性进行更改。

代码

这如何在代码中翻译?假设您实际知道需要接收多少数据,改进的代码将如下所示:

Dim bytesRemaining As Integer = Buffer.Length
Dim sb As New StringBuilder
While bytesRemaining > 0
    Dim bytes As Integer = cSocket.Receive(Buffer,
                                           bytesRemaining, SocketFlags.None)
    bytesRemaining -= bytes
    sb.Append(ASCII.GetString(Buffer, 0, bytes))
End While
mes = sb.ToString()

循环中的条件消失了,因为如果我们没有收到很多字节,我们不想退出,我们想继续阅读。 bytesRemaining保持仍在接收的字节数的运行计数。

与您的问题无关,但我已将mes字符串连接替换为StringBuilder。可能你会创建很多新的字符串,所有人(除了最后一个)都需要进行垃圾回收。