Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit74b868f

Browse files
authored
gh-111246: Remove listening Unix socket on close (#111483)
Try to clean up the socket file we create so we don't add unused noise to the file system.
1 parentf88caab commit74b868f

File tree

5 files changed

+126
-2
lines changed

5 files changed

+126
-2
lines changed

‎Doc/library/asyncio-eventloop.rst

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -778,7 +778,7 @@ Creating network servers
778778
*, sock=None, backlog=100, ssl=None, \
779779
ssl_handshake_timeout=None, \
780780
ssl_shutdown_timeout=None, \
781-
start_serving=True)
781+
start_serving=True, cleanup_socket=True)
782782
783783
Similar to:meth:`loop.create_server` but works with the
784784
:py:const:`~socket.AF_UNIX` socket family.
@@ -788,6 +788,10 @@ Creating network servers
788788
:class:`str`,:class:`bytes`, and:class:`~pathlib.Path` paths
789789
are supported.
790790

791+
If *cleanup_socket* is True then the Unix socket will automatically
792+
be removed from the filesystem when the server is closed, unless the
793+
socket has been replaced after the server has been created.
794+
791795
See the documentation of the:meth:`loop.create_server` method
792796
for information about arguments to this method.
793797

@@ -802,6 +806,10 @@ Creating network servers
802806

803807
Added the *ssl_shutdown_timeout* parameter.
804808

809+
..versionchanged::3.13
810+
811+
Added the *cleanup_socket* parameter.
812+
805813

806814
..coroutinemethod::loop.connect_accepted_socket(protocol_factory, \
807815
sock, *, ssl=None, ssl_handshake_timeout=None, \

‎Doc/whatsnew/3.13.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,13 @@ array
149149
It can be used instead of ``'u'`` type code, which is deprecated.
150150
(Contributed by Inada Naoki in:gh:`80480`.)
151151

152+
asyncio
153+
-------
154+
155+
*:meth:`asyncio.loop.create_unix_server` will now automatically remove
156+
the Unix socket when the server is closed.
157+
(Contributed by Pierre Ossman in:gh:`111246`.)
158+
152159
copy
153160
----
154161

‎Lib/asyncio/unix_events.py

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ class _UnixSelectorEventLoop(selector_events.BaseSelectorEventLoop):
6464
def__init__(self,selector=None):
6565
super().__init__(selector)
6666
self._signal_handlers= {}
67+
self._unix_server_sockets= {}
6768

6869
defclose(self):
6970
super().close()
@@ -284,7 +285,7 @@ async def create_unix_server(
284285
sock=None,backlog=100,ssl=None,
285286
ssl_handshake_timeout=None,
286287
ssl_shutdown_timeout=None,
287-
start_serving=True):
288+
start_serving=True,cleanup_socket=True):
288289
ifisinstance(ssl,bool):
289290
raiseTypeError('ssl argument must be an SSLContext or None')
290291

@@ -340,6 +341,15 @@ async def create_unix_server(
340341
raiseValueError(
341342
f'A UNIX Domain Stream Socket was expected, got{sock!r}')
342343

344+
ifcleanup_socket:
345+
path=sock.getsockname()
346+
# Check for abstract socket. `str` and `bytes` paths are supported.
347+
ifpath[0]notin (0,'\x00'):
348+
try:
349+
self._unix_server_sockets[sock]=os.stat(path).st_ino
350+
exceptFileNotFoundError:
351+
pass
352+
343353
sock.setblocking(False)
344354
server=base_events.Server(self, [sock],protocol_factory,
345355
ssl,backlog,ssl_handshake_timeout,
@@ -460,6 +470,27 @@ def cb(fut):
460470
self.remove_writer(fd)
461471
fut.add_done_callback(cb)
462472

473+
def_stop_serving(self,sock):
474+
# Is this a unix socket that needs cleanup?
475+
ifsockinself._unix_server_sockets:
476+
path=sock.getsockname()
477+
else:
478+
path=None
479+
480+
super()._stop_serving(sock)
481+
482+
ifpathisnotNone:
483+
prev_ino=self._unix_server_sockets[sock]
484+
delself._unix_server_sockets[sock]
485+
try:
486+
ifos.stat(path).st_ino==prev_ino:
487+
os.unlink(path)
488+
exceptFileNotFoundError:
489+
pass
490+
exceptOSErroraserr:
491+
logger.error('Unable to clean up listening UNIX socket '
492+
'%r: %r',path,err)
493+
463494

464495
class_UnixReadPipeTransport(transports.ReadTransport):
465496

‎Lib/test/test_asyncio/test_server.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
importasyncio
2+
importos
3+
importsocket
24
importtime
35
importthreading
46
importunittest
@@ -177,6 +179,80 @@ async def serve(*args):
177179

178180

179181

182+
# Test the various corner cases of Unix server socket removal
183+
classUnixServerCleanupTests(unittest.IsolatedAsyncioTestCase):
184+
@socket_helper.skip_unless_bind_unix_socket
185+
asyncdeftest_unix_server_addr_cleanup(self):
186+
# Default scenario
187+
withtest_utils.unix_socket_path()asaddr:
188+
asyncdefserve(*args):
189+
pass
190+
191+
srv=awaitasyncio.start_unix_server(serve,addr)
192+
193+
srv.close()
194+
self.assertFalse(os.path.exists(addr))
195+
196+
@socket_helper.skip_unless_bind_unix_socket
197+
asyncdeftest_unix_server_sock_cleanup(self):
198+
# Using already bound socket
199+
withtest_utils.unix_socket_path()asaddr:
200+
asyncdefserve(*args):
201+
pass
202+
203+
sock=socket.socket(socket.AF_UNIX,socket.SOCK_STREAM)
204+
sock.bind(addr)
205+
206+
srv=awaitasyncio.start_unix_server(serve,sock=sock)
207+
208+
srv.close()
209+
self.assertFalse(os.path.exists(addr))
210+
211+
@socket_helper.skip_unless_bind_unix_socket
212+
asyncdeftest_unix_server_cleanup_gone(self):
213+
# Someone else has already cleaned up the socket
214+
withtest_utils.unix_socket_path()asaddr:
215+
asyncdefserve(*args):
216+
pass
217+
218+
sock=socket.socket(socket.AF_UNIX,socket.SOCK_STREAM)
219+
sock.bind(addr)
220+
221+
srv=awaitasyncio.start_unix_server(serve,sock=sock)
222+
223+
os.unlink(addr)
224+
225+
srv.close()
226+
227+
@socket_helper.skip_unless_bind_unix_socket
228+
asyncdeftest_unix_server_cleanup_replaced(self):
229+
# Someone else has replaced the socket with their own
230+
withtest_utils.unix_socket_path()asaddr:
231+
asyncdefserve(*args):
232+
pass
233+
234+
srv=awaitasyncio.start_unix_server(serve,addr)
235+
236+
os.unlink(addr)
237+
sock=socket.socket(socket.AF_UNIX,socket.SOCK_STREAM)
238+
sock.bind(addr)
239+
240+
srv.close()
241+
self.assertTrue(os.path.exists(addr))
242+
243+
@socket_helper.skip_unless_bind_unix_socket
244+
asyncdeftest_unix_server_cleanup_prevented(self):
245+
# Automatic cleanup explicitly disabled
246+
withtest_utils.unix_socket_path()asaddr:
247+
asyncdefserve(*args):
248+
pass
249+
250+
srv=awaitasyncio.start_unix_server(serve,addr,cleanup_socket=False)
251+
252+
srv.close()
253+
self.assertTrue(os.path.exists(addr))
254+
255+
180256
@unittest.skipUnless(hasattr(asyncio,'ProactorEventLoop'),'Windows only')
181257
classProactorStartServerTests(BaseStartServer,unittest.TestCase):
182258

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
:meth:`asyncio.loop.create_unix_server` will now automatically remove the
2+
Unix socket when the server is closed.

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp