@@ -202,6 +202,14 @@ async def recv_until():
202
202
# ProactorEventLoop could deliver hello
203
203
self .assertTrue (data .endswith (b'world' ))
204
204
205
+ # After the first connect attempt before the listener is ready,
206
+ # the socket needs time to "recover" to make the next connect call.
207
+ # On Linux, a second retry will do. On Windows, the waiting time is
208
+ # unpredictable; and on FreeBSD the socket may never come back
209
+ # because it's a loopback address. Here we'll just retry for a few
210
+ # times, and have to skip the test if it's not working. See also:
211
+ # https://stackoverflow.com/a/54437602/3316267
212
+ # https://lists.freebsd.org/pipermail/freebsd-current/2005-May/049876.html
205
213
async def _basetest_sock_connect_racing (self , listener , sock ):
206
214
listener .bind (('127.0.0.1' , 0 ))
207
215
addr = listener .getsockname ()
@@ -212,30 +220,26 @@ async def _basetest_sock_connect_racing(self, listener, sock):
212
220
task .cancel ()
213
221
214
222
listener .listen (1 )
215
- i = 0
216
- while True :
223
+
224
+ skip_reason = "Max retries reached"
225
+ for i in range (128 ):
217
226
try :
218
227
await self .loop .sock_connect (sock , addr )
219
- break
220
- except ConnectionRefusedError : # on Linux we need another retry
221
- await self .loop .sock_connect (sock , addr )
222
- break
223
- except OSError as e : # on Windows we need more retries
224
- # A connect request was made on an already connected socket
225
- if getattr (e , 'winerror' , 0 ) == 10056 :
226
- break
228
+ except ConnectionRefusedError as e :
229
+ skip_reason = e
230
+ except OSError as e :
231
+ skip_reason = e
227
232
228
- # https://stackoverflow.com/a/54437602/3316267
233
+ # Retry only for this error:
234
+ # [WinError 10022] An invalid argument was supplied
229
235
if getattr (e , 'winerror' , 0 ) != 10022 :
230
- raise
231
- i += 1
232
- if i >= 128 :
233
- raise # too many retries
234
- # avoid touching event loop to maintain race condition
235
- time .sleep (0.01 )
236
-
237
- # FIXME: https://bugs.python.org/issue30064#msg370143
238
- @unittest .skipIf (True , "unstable test" )
236
+ break
237
+ else :
238
+ # success
239
+ return
240
+
241
+ self .skipTes
8000
t (skip_reason )
242
+
239
243
def test_sock_client_racing (self ):
240
244
with test_utils .run_test_server () as httpd :
241
245
sock = socket .socket ()
@@ -251,6 +255,8 @@ def test_sock_client_racing(self):
251
255
with listener , sock :
252
256
self .loop .run_until_complete (asyncio .wait_for (
253
257
self ._basetest_sock_send_racing (listener , sock ), 10 ))
258
+
259
+ def test_sock_client_connect_racing (self ):
254
260
listener = socket .socket ()
255
261
sock = socket .socket ()
256
262
with listener , sock :
0 commit comments