我目前正在尝试了解套接字的工作方式。
我遵循了一个在线教程&蟒蛇HOWTO
我有一个服务器:
#!/usr/bin/env python3
import socket
HOST = '127.0.0.1' #standard loopback interface address (localhost)
PORT = 9999
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serversocket.bind((HOST, PORT))
serversocket.listen()
(clientsocket, address) = serversocket.accept()
with clientsocket:
print('Connected by', address)
while True:
data = clientsocket.recv(1024)
if not data:
break
clientsocket.sendall(data)
clientsocket.shutdown(socket.SHUT_RDWR)
clientsocket.close()
和一个客户端:
#!/usr/bin/env python3
import socket
HOST = '127.0.0.1' #server hostname or IP address
PORT = 9999
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
s.sendall(b'Hello world!')
data = s.recv(1024)
s.shutdown(socket.SHUT_RDWR)
s.close
print('Received', repr(data))
服务器监听连接,接受它,并回显它接收到的任何内容。
在python HOWTO中,强调始终关闭套接字。
现在,当我在不同的终端中运行这两个脚本时,客户端会按预期操作:
Received b'Hello world!'
带有服务器的终端给了我以下错误:
Connected by ('127.0.0.1, 42780')
Traceback (most recent call last):
File "echo-server.py", line 19, in <module>
clientsocket.shutdown(socket.SHUT_RDWR)
OSError: [Errno 9] Bad file descriptor
通过环顾四周,我了解到这是因为关闭了Python文件;外部";,即不是来自文件对象的close((,我认为这意味着我试图调用socket.shutdown()
的套接字已经关闭。
现在,当我在服务器脚本中注释第19行时
#clientsocket.shutdown(socket.SHUT_RWDR)
一切都按预期进行,没有任何错误。
终端显示
Connected by ('127.0.0.1, 42780')
和
Received b'Hello world!'
据我所知,这种行为是由with语句引起的。
现在来谈谈我的实际问题:
- with语句是否通过完成该任务本身而使调用
socket.shutdown()
变得不必要 - 如果是,调用
socket.close()
是否仍然是必要的,还是由with语句完成?(评论这句话并没有给我任何不同的结果(
最后,我想确保如何从一开始就正确关闭套接字,因为HOWTO非常强调正确的形式。
close
在with
中是不必要的,因为它在退出with
块时会自动调用close,但在with
退出之前,shutdown
仍然可以在其内部调用:
with clientsocket:
print('Connected by', address)
while True:
data = clientsocket.recv(1024)
if not data:
clientsocket.shutdown(socket.SHUT_RDWR)
break
clientsocket.sendall(data)
正如@Peter Wood所指出的,文档中确实包含了我问题的答案:
在3.2版中更改:添加了对上下文管理器协议的支持。退出上下文管理器相当于调用close((。
此外:
垃圾回收套接字时,套接字会自动关闭,但建议显式关闭((套接字,或在套接字周围使用with语句。
由于对已关闭的fileObject调用fileObject.close()
不会产生错误,因此注释特定的行输出不会导致任何不同的结果。
我的解释是:
不打算在with
语句中的套接字上显式调用socket.shutdown()
。
在with
语句中的套接字上调用socket.close()
是不必要的。