如果套接字仍然连接,EndReceive是否应该返回零?

7

我在套接字上进行以下BeginReceive调用:

m_socket.BeginReceive(m_buffer, 0, m_buffer.Length, SocketFlags.Partial, this.ReceiveCallback, null);

在我的类中,我调用ReceiveCallback函数。
try {
    int bytesReadFromSocket = m_socket.EndReceive(ar);
    if(bytesReadFromSocket > 0) {
         // Do some processing
    }
}
finally {
   if(m_socket.Connected) m_socket.BeginReceive(m_buffer, 0, m_buffer.Length, SocketFlags.Partial, this.ReceiveCallback, null);
}

我遇到的问题是EndReceive返回0,但m_socket.Connected返回true,所以我再次调用BeginReceive。这在一个紧密的循环中发生,它永远不会停止。从文档中不清楚EndReceive何时返回零。我认为只有当套接字关闭时才会发生,但这似乎不是真的。
因此,问题仍然存在,EndReceive在什么情况下会返回零?

看看这个。http://stackoverflow.com/questions/3970825/when-does-endreceive-return-zero-bytes除了这三种情况,它好像会返回0字节。 - Levi Fuller
Levi,我已经看过那篇文章了。它并不是我所问的问题相关的。我特别询问EndReceive的返回值,如果返回值为零是否意味着套接字上将不再有更多数据可用。 - bpeikes
2个回答

6

Socket.EndReceive()在一个特定的情况下返回0:远程主机已经开始或确认了优雅关闭序列(例如,对于一个基于.NET Socket的程序,在调用Socket.Shutdown()时使用SocketShutdown.SendSocketShutdown.Both)。

然而需要注意的是,在套接字最终关闭之前,它仍然处于"连接"状态。

你不应该使用Connected属性来确定是否应该从套接字发起另一个读取。相反,由于返回值0专门用于指示不会再发送更多数据,因此,你应该简单地检查EndReceive()的返回值,如果这个值是一个正数(即不为零),则再次调用BeginReceive()


谢谢。我在想,如果套接字没有从另一端正确关闭,那么调用“Socket.Connected”进行BeginReceive的检查可能不是有效的。事实上,如果服务器断开连接但客户端没有确认,Connected可能会有时候被卡住。 - bpeikes
我猜这取决于你对“卡住”的定义。如果客户端未能确认关闭,但仍然关闭了其端口,或者只是退出进程而没有清理,则服务器仍将看到完成回调被调用,但当您调用EndReceive()时,您将收到一个异常(表示连接已重置),而不是0返回值。无论哪种方式,服务器最终都会知道套接字不再连接。 :) - Peter Duniho
我在EndReceive上没有收到异常,只是得到了一个零的返回值,并且我认为零并不一定意味着有错误。你认为客户端应该在ReceiveCallback中关闭套接字吗?如果EndReceive返回零的话? - bpeikes
返回值为0表示另一端调用了关闭操作。每个端点在发送完数据后应该关闭套接字(而不是关闭)。当每个端点已经关闭了套接字并且已经完成了一个接收操作,接收到的数据长度为0字节(无论是在关闭之前还是之后),那么它们就可以关闭套接字了。 - Peter Duniho
当EndReceive返回零时,我应该在客户端中调用Close、Disconnect还是Shutdown?或者它们的组合? - bpeikes
1
这取决于你还有什么任务要完成。如果你已经完成了自己发送数据的工作,并且已经调用了 Shutdown(SocketShutdown.Send),那么你可以在那个时候关闭套接字。如果你还有数据要发送,那么你只需要在某个地方做个标记(例如,在连接状态中存储的私有标志...在许多情况下,人们已经在维护某种连接状态),表示远程主机已经关闭,然后当你完成发送时,调用 Shutdown(SocketShutdown.Both),然后关闭套接字。 - Peter Duniho

-1
有时候我们在测试TCP连接时,忘记初始化缓冲数组。当它为null或者为空时,EndReceive()总会返回0。我曾经有过一个很愚蠢的经历。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接