python3 socket programming howto提供了此代码段
class MySocket:
"""demonstration class only
- coded for clarity, not efficiency
"""
def __init__(self, sock=None):
if sock is None:
self.sock = socket.socket(
socket.AF_INET, socket.SOCK_STREAM)
else:
self.sock = sock
def connect(self, host, port):
self.sock.connect((host, port))
def mysend(self, msg):
totalsent = 0
while totalsent < MSGLEN:
sent = self.sock.send(msg[totalsent:])
if sent == 0:
raise RuntimeError("socket connection broken")
totalsent = totalsent + sent
def myreceive(self):
chunks = []
bytes_recd = 0
while bytes_recd < MSGLEN:
chunk = self.sock.recv(min(MSGLEN - bytes_recd, 2048))
if chunk == b'':
raise RuntimeError("socket connection broken")
chunks.append(chunk)
bytes_recd = bytes_recd + len(chunk)
return b''.join(chunks)
如果socket send
方法返回0,则发送循环被中断。
这段代码背后的逻辑是当send
方法返回'0字节发送'时,套接字连接的发送方应该放弃发送数据的努力。这对于recv
方法肯定是正确的,其中在阻塞模式下为套接字读取的零字节应该被解释为EOF
,因此读取方应该放弃。
但是我无法理解send
方法在哪些情况下可以返回零。我对python套接字的理解是send
由于OS级别的缓冲而立即返回。如果缓冲区已满,send
将阻塞,或者如果在远程端关闭连接,则会引发异常。
最后假设send
返回零而不引发异常:这是否真的表明所有未来的send
调用都将返回零?
我已经做了一些测试(尽管在OS X上只使用了连接到::1
的套接字)并且无法找到send
返回0的情况。
修改
HOWTO说:
但是,如果您计划重新使用套接字进行进一步传输,则需要 意识到插座上没有EOT。我再说一遍:如果是套接字 处理0字节后发送或recv返回,连接已经 破碎。如果连接尚未断开,您可以等待recv 永远,因为套接字不会告诉你什么都没有 更多内容(现在)。
很容易找到recv
返回0的情况:当远程(发送)方调用socket.shutdown(SHUT_WR)
时,接收方的其他recv
将返回{{1}并且不会引发任何异常。
我正在寻找一个具体示例,您可以在其中显示从0
接收0零表示断开连接(在发送时将继续返回0)。
答案 0 :(得分:5)
在看到问题后,我被震惊了,因为send
C调用可以返回0个字节并且连接当然仍然存活(套接字不能简单地在给定时刻发送更多字节)
我决定&#34;使用来源&#34;除非我非常错(这可能一直是经常发生),这是HOWTO中的一个错误。
链
send
是sock_send
sock_send
依次拨打电话sock_call
sock_call
依次拨打电话sock_call_ex
sock_call
依次调用sock_send_impl
(已从sock_send
开始向下传递)放卷:
sock_send_impl
使用true
false
或return (ctx->result >= 0)
(1或0)
sock_call_ex
返回
-1
返回sock_send_impl
false
如果0
返回sock_send_impl
true
sock_call
透明地返回此值。
sock_send
为NULL
返回-1
(因为已设置错误并会引发异常)
从ctx->result
0
的{{1}}
sock_call
是ctx->result
中C调用send
写入的字节数。
链表示如果发送了sock_send_impl
个字节,则没有错误,这实际上是一个潜在的真实插座情况。
如果我的逻辑错误,请有人告诉我。
答案 1 :(得分:3)
我可能错了,但我认为你正在寻找一个不可能的情况......
正如@mementum在他的回答中所示,理论上,当没有错误时套接字可以返回零,但也没有数据发送。
但是,如图elsewhere on SO所示,这只能在非常具体的情况下发生。根据我的经验(并且在对已接受答案的评论中也包含了这些内容),当网络拥塞时,您只能在非阻塞套接字上获得零结果。现在Python套接字默认是阻塞,这意味着内核应该等到有空间再获取更多数据然后返回排队的字节数。根据定义,这永远不会为零。
所以,把它们放在一起,因为你的代码片段没有重置套接字类型 - 例如使用set_blocking
函数 - 它使用阻塞套接字,因此不能返回零,因此无法达到识别的路径mementum。
这可以通过以下事实得到支持:无论您做什么,都无法触发特定的代码行。