我正在尝试测试一些在断开连接后重新连接到服务器的代码。这在测试之外完全正常,但是在运行测试时它无法确认套接字已断开连接。
我正在使用Gevent Stream Server来模拟真实的侦听服务器:
import gevent.server
from gevent import queue
class TestServer(gevent.server.StreamServer):
def __init__(self, *args, **kwargs):
super(TestServer, self).__init__(*args, **kwargs)
self.sockets = {}
def handle(self, socket, address):
self.sockets[address] = (socket, queue.Queue())
socket.sendall('testing the connection\r\n')
gevent.spawn(self.recv, address)
def recv(self, address):
socket = self.sockets[address][0]
queue = self.sockets[address][1]
print 'Connection accepted %s:%d' % address
try:
for data in socket.recv(1024):
queue.put(data)
except:
pass
def murder(self):
self.stop()
for sock in self.sockets.iteritems():
print sock
sock[1][0].shutdown(socket.SHUT_RDWR)
sock[1][0].close()
self.sockets = {}
def run_server():
test_server = TestServer(('127.0.0.1', 10666))
test_server.start()
return test_server
我的测试看起来像这样:
def test_can_reconnect(self):
test_server = run_server()
client_config = {'host': '127.0.0.1', 'port': 10666}
client = Connection('test client', client_config, get_config())
client.connect()
assert client.socket_connected
test_server.murder()
#time.sleep(4) #tried sleeping. no dice.
assert not client.socket_connected
assert client.server_disconnect
test_server = run_server()
client.reconnect()
assert client.socket_connected
在assert not client.socket_connected
失败。
我在recv期间检测到“not data”。如果它是None,那么我设置一些变量,以便其他代码可以决定是否重新连接(如果是user_disconnect则不重新连接,等等)。这种行为起作用,过去一直对我有用,我直到现在才尝试对它进行测试。套接字连接和本地函数范围有什么奇怪之处吗?就像停止服务器后连接仍然存在一样。
我正在尝试测试的代码是开放的:https://github.com/kyleterry/tenyks.git
如果您运行测试,您将看到我正在尝试修复的测试失败。
答案 0 :(得分:2)
尝试使用真正的套接字运行单元测试是一个艰难的行。这将是棘手的,因为一次只能运行一组测试,因为将使用服务器端口,并且随着套接字的设置和拆除,它将会变慢。最重要的是,如果这实际上是一个单元测试,你不想测试套接字,只需要使用套接字的代码。
如果你模拟套接字调用,你可以从模拟的代码中抛出异常,并确保使用套接字的代码做正确的事情。你不需要一个真正的套接字来确保被测试的类做正确的事情,你可以伪造它,如果你可以将套接字调用包装在一个对象中。在构建类时传递对套接字对象的引用,然后您就可以开始了。
我的建议是将套接字调用包装在一个支持sendall,recv和您在套接字上调用的所有方法的类中。然后你可以用TestReconnectSocket(或其他)替换实际的Socket类并运行你的测试。
看看mox,一个python模拟框架。
答案 1 :(得分:0)
模糊的回应,但我的立即反应是你的recv()调用阻塞并使套接字保持活动状态 - 你是否尝试使套接字无阻塞,并在关闭时捕获错误?
答案 2 :(得分:0)
在测试这样的套接字时要记住的一件事是,操作系统不喜欢在使用后立即重新打开套接字。您可以设置套接字选项以告知它继续并重新使用它。在创建套接字后立即设置套接字的选项:
mysocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
希望这可以解决您的问题。您可能必须在服务器端和客户端都这样做,具体取决于哪一个给您带来问题。
答案 3 :(得分:0)
shutdown(socket.SHUT_RDWR)
,因此这似乎不是problem with recv blocking。gevent.socket.socket.recv
,因此请检查您的gevent
版本,recv()
存在导致block if the underlying file descriptor is closed问题的问题}(版本< v0.13.0
)gevent.sleep()
合作收益,并让客户有机会退出recv()
来电。