@@ -202,6 +202,14 @@ async def recv_until():
202202 # ProactorEventLoop could deliver hello
203203 self .assertTrue (data .endswith (b'world' ))
204204
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
205213 async def _basetest_sock_connect_racing (self , listener , sock ):
206214 listener .bind (('127.0.0.1' , 0 ))
207215 addr = listener .getsockname ()
@@ -212,30 +220,26 @@ async def _basetest_sock_connect_racing(self, listener, sock):
212220 task .cancel ()
213221
214222 listener .listen (1 )
215- i = 0
216- while True :
223+
224+ skip_reason = "Max retries reached"
225+ for i in range (128 ):
217226 try :
218227 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
227232
228- # https://stackoverflow.com/a/54437602/3316267
233+ # Retry only for this error:
234+ # [WinError 10022] An invalid argument was supplied
229235 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 .skipTest (skip_reason )
242+
239243 def test_sock_client_racing (self ):
240244 with test_utils .run_test_server () as httpd :
241245 sock = socket .socket ()
@@ -251,6 +255,8 @@ def test_sock_client_racing(self):
251255 with listener , sock :
252256 self .loop .run_until_complete (asyncio .wait_for (
253257 self ._basetest_sock_send_racing (listener , sock ), 10 ))
258+
259+ def test_sock_client_connect_racing (self ):
254260 listener = socket .socket ()
255261 sock = socket .socket ()
256262 with listener , sock :
0 commit comments