Windows sockets have some strange behavior when it comes to WSAECONNREFUSED (which means backlog full or port not available, see https://stackoverflow.com/a/10308338/851737). If Windows detects one of these conditions, it retries (up to) two times with an interval of 0.5s. This means it takes at least 1 second to detect WSAECONNREFUSED on a socket connection attempt (http://support.microsoft.com/kb/175523/en-us).
Is there any way to speed up this detection without messing with the registry values? I need to simulate refusing socket connections in unittests. A workaround like simulating a refused connection with raw sockets would be acceptable, too.
Here is a simple Python script demonstrating the issue:
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()
It's not exactly what you asked about. But if you need this in the unittests only, mock library would be useful.
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()
Here is my solution based on dmitry-vakhrushev's answer which is patching the connect method more intelligent:
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With