为什么我的Python线程中的socket并不总是正常关闭(即如果我多次运行程序)
我有以下这段代码(里面有很多调试信息)。如果我在短时间内连续运行几次,常常会出现“地址正在使用”的错误。不过,这个错误并不是每次都会发生。
socket.error: [Errno 98] Address already in use
当我没有遇到错误时,输出结果是这样的:
trying to recv ('127.0.0.1', 38041)
recved
from client --> None genuine without this seal!
shutting down con
closing con
done closing con
shutting down
running server shutdown
running server close
done closing
done shutting down
以下是我的代码:
import socket
from threading import Thread
from time import sleep
from subprocess import Popen, PIPE, STDOUT
def shutdown_thread(t):
print "shutting down"
t.shutdown()
while t.isAlive():
sleep(.1)
print "done shutting down"
def send_with_netcat(msg):
nc = Popen(
['nc', '127.0.0.1', '8000'],
stdin=PIPE,
stdout=PIPE,
stderr=STDOUT)
result = nc.communicate(msg)
return result
class Server(Thread):
is_shutdown = False
def __init__(self):
super(Server, self).__init__()
self.start_server()
def start_server(self):
self.server = socket.socket(
socket.AF_INET,
socket.SOCK_STREAM)
# "A socket is a 5 tuple (proto, local addr, local port,
# remote addr, remote port). SO_REUSEADDR just says that you
# can reuse local addresses. The 5 tuple still must be
# unique!"
self.server.setsockopt(
socket.SOL_SOCKET,
socket.SO_REUSEADDR,
1)
self.server = socket.socket(
socket.AF_INET,
socket.SOCK_STREAM)
# bind the socket
# ERROR HAPPENS HERE, HOW TO DEAL DEAL WITH OR AVOID?
self.server.bind(('127.0.0.1', 8000))
self.server.listen(5)
def shutdown(self):
self.is_shutdown = True
def run(self):
while not self.is_shutdown:
con, addr = self.server.accept()
print "trying to recv", addr
buf = con.recv(128)
print "recved"
if len(buf) > 0:
print "from client --> ", buf
print "shutting down con"
con.shutdown(socket.SHUT_RDWR)
print "closing con"
con.close()
print "done closing con"
sleep(.1)
print "running server shutdown"
self.server.shutdown(socket.SHUT_RDWR)
print "running server close"
self.server.close()
print "done closing"
if __name__ == '__main__':
s = Server()
s.start()
send_with_netcat("None genuine without this seal!")
shutdown_thread(s)
sleep(5)
如果你觉得在GitHub上看起来更清晰,可以在这里查看同样的代码。
奇怪的是,当我试图发这个帖子时,花了比预期更多的时间。这会不会是因为我的机器上有很多连接在随机化客户端的nc
连接呢?
感谢你对这个问题的任何解释。
1 个回答
2
在你的 start_server()
方法里,你首先在 self.server
中打开了一个套接字,然后你给这个套接字设置了 SO_REUSEADDR
选项。接着你又调用了一次 socket.socket()
,这就把你之前的 setsockopt()
设置给覆盖掉了。试着删除第二次的 socket.socket()
调用,这样就能让 SO_REUSEADDR
选项生效了。