快速检测或模拟WSAECONNREFUSED

当涉及到WSAECONNREFUSED(意味着积压已满或端口不可用,请参阅https://stackoverflow.com/a/10308338/851737 )时,Windows套接字有一些奇怪的行为。 如果Windows检测到这些情况之一,则会以0.5秒的间隔重试(最多)两次。 这意味着在套接字连接尝试上检测WSAECONNREFUSED至less需要1秒( http://support.microsoft.com/kb/175523/en-us )。

有没有什么办法来加速这个检测,而不会搞乱registry值? 我需要在unit testing中模拟拒绝套接字连接。 类似于使用原始套接字模拟拒绝连接的解决方法也是可以接受的。

这是一个简单的Python脚本,展示了这个问题:

import errno import socket import time PORT = 50123 def main(): s = socket.socket() s.bind(('127.0.0.1', PORT)) s.listen(0) client = socket.socket() client.connect(('127.0.0.1', PORT)) client2 = socket.socket() start = time.time() try: client2.connect(('127.0.0.1', PORT)) except socket.error as e: assert e.errno == errno.WSAECONNREFUSED print 'connection attempt took', time.time() - start finally: client2.close() client.close() s.close() if __name__ == '__main__': main() 

这不完全是你问的。 但是如果你只在单位测试中需要这个, 模拟库会很有用。

 import errno import socket import time import mock PORT = 50123 def connect_mock(*agrs): raise socket.error(errno.WSAECONNREFUSED, "Testing") def main(): s = socket.socket() s.bind(('127.0.0.1', PORT)) s.listen(0) client = socket.socket() client.connect(('127.0.0.1', PORT)) client2 = socket.socket() start = time.time() with mock.patch('socket.socket.connect', connect_mock): try: client2.connect(('127.0.0.1', PORT)) print "done" except socket.error as e: assert e.errno == errno.WSAECONNREFUSED print 'connection attempt took', time.time() - start finally: client2.close() client.close() s.close() if __name__ == '__main__': main() 

这是我的解决方案基于德米特里 – vakhrushev的答案是修补连接方法更聪明:

 if sys.platform == 'win32': n_calls = [0] org_connect = socket.socket.connect def refusing_connect(*args): if n_calls[0] < 2: n_calls[0] += 1 raise socket.error(errno.WSAECONNREFUSED, "Testing") return org_connect(*args) # patch socket.connect to speed up WSAECONNREFUSED detection patcher = mock.patch('socket.socket.connect', refusing_connect) patcher.start() self.addCleanup(patcher.stop)