Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Updated socketserver.py + test_socketserver.py
  • Loading branch information
terryluan12 committed Dec 30, 2025
commit 20b9c56b0b29b177026a36873aa1e8ee5f96e63b
30 changes: 23 additions & 7 deletions Lib/socketserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,10 +127,7 @@ class will essentially render the service "deaf" while one request is
import selectors
import os
import sys
try:
import threading
except ImportError:
import dummy_threading as threading
import threading
from io import BufferedIOBase
from time import monotonic as time

Expand All @@ -144,6 +141,8 @@ class will essentially render the service "deaf" while one request is
__all__.extend(["UnixStreamServer","UnixDatagramServer",
"ThreadingUnixStreamServer",
"ThreadingUnixDatagramServer"])
if hasattr(os, "fork"):
__all__.extend(["ForkingUnixStreamServer", "ForkingUnixDatagramServer"])

# poll/select have the advantage of not requiring any extra file descriptor,
# contrarily to epoll/kqueue (also, they require a single syscall).
Expand Down Expand Up @@ -190,6 +189,7 @@ class BaseServer:
- address_family
- socket_type
- allow_reuse_address
- allow_reuse_port

Instance variables:

Expand Down Expand Up @@ -294,8 +294,7 @@ def handle_request(self):
selector.register(self, selectors.EVENT_READ)

while True:
ready = selector.select(timeout)
if ready:
if selector.select(timeout):
return self._handle_request_noblock()
else:
if timeout is not None:
Expand Down Expand Up @@ -428,6 +427,7 @@ class TCPServer(BaseServer):
- socket_type
- request_queue_size (only for stream sockets)
- allow_reuse_address
- allow_reuse_port

Instance variables:

Expand All @@ -445,6 +445,8 @@ class TCPServer(BaseServer):

allow_reuse_address = False

allow_reuse_port = False

def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True):
"""Constructor. May be extended, do not override."""
BaseServer.__init__(self, server_address, RequestHandlerClass)
Expand All @@ -464,8 +466,15 @@ def server_bind(self):
May be overridden.

"""
if self.allow_reuse_address:
if self.allow_reuse_address and hasattr(socket, "SO_REUSEADDR"):
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# Since Linux 6.12.9, SO_REUSEPORT is not allowed
# on other address families than AF_INET/AF_INET6.
if (
self.allow_reuse_port and hasattr(socket, "SO_REUSEPORT")
and self.address_family in (socket.AF_INET, socket.AF_INET6)
):
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
self.socket.bind(self.server_address)
self.server_address = self.socket.getsockname()

Expand Down Expand Up @@ -522,6 +531,8 @@ class UDPServer(TCPServer):

allow_reuse_address = False

allow_reuse_port = False

socket_type = socket.SOCK_DGRAM

max_packet_size = 8192
Expand Down Expand Up @@ -723,6 +734,11 @@ class ThreadingUnixStreamServer(ThreadingMixIn, UnixStreamServer): pass

class ThreadingUnixDatagramServer(ThreadingMixIn, UnixDatagramServer): pass

if hasattr(os, "fork"):
class ForkingUnixStreamServer(ForkingMixIn, UnixStreamServer): pass

class ForkingUnixDatagramServer(ForkingMixIn, UnixDatagramServer): pass

class BaseRequestHandler:

"""Base class for request handler classes.
Expand Down
27 changes: 6 additions & 21 deletions Lib/test/test_socketserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import select
import signal
import socket
import tempfile
import threading
import unittest
import socketserver
Expand All @@ -21,21 +20,18 @@


test.support.requires("network")
test.support.requires_working_socket(module=True)


TEST_STR = b"hello world\n"
HOST = socket_helper.HOST

HAVE_UNIX_SOCKETS = hasattr(socket, "AF_UNIX")
requires_unix_sockets = unittest.skipUnless(HAVE_UNIX_SOCKETS,
'requires Unix sockets')
HAVE_FORKING = hasattr(os, "fork")
HAVE_FORKING = test.support.has_fork_support
requires_forking = unittest.skipUnless(HAVE_FORKING, 'requires forking')

def signal_alarm(n):
"""Call signal.alarm when it exists (i.e. not on Windows)."""
if hasattr(signal, 'alarm'):
signal.alarm(n)

# Remember real select() to avoid interferences with mocking
_real_select = select.select

Expand All @@ -46,14 +42,6 @@ def receive(sock, n, timeout=test.support.SHORT_TIMEOUT):
else:
raise RuntimeError("timed out on %r" % (sock,))

if HAVE_UNIX_SOCKETS and HAVE_FORKING:
class ForkingUnixStreamServer(socketserver.ForkingMixIn,
socketserver.UnixStreamServer):
pass

class ForkingUnixDatagramServer(socketserver.ForkingMixIn,
socketserver.UnixDatagramServer):
pass

@test.support.requires_fork() # TODO: RUSTPYTHON, os.fork is currently only supported on Unix-based systems
@contextlib.contextmanager
Expand All @@ -75,12 +63,10 @@ class SocketServerTest(unittest.TestCase):
"""Test all socket servers."""

def setUp(self):
signal_alarm(60) # Kill deadlocks after 60 seconds.
self.port_seed = 0
self.test_files = []

def tearDown(self):
signal_alarm(0) # Didn't deadlock.
reap_children()

for fn in self.test_files:
Expand All @@ -96,8 +82,7 @@ def pickaddr(self, proto):
else:
# XXX: We need a way to tell AF_UNIX to pick its own name
# like AF_INET provides port==0.
dir = None
fn = tempfile.mktemp(prefix='unix_socket.', dir=dir)
fn = socket_helper.create_unix_domain_name()
self.test_files.append(fn)
return fn

Expand Down Expand Up @@ -211,7 +196,7 @@ def test_ThreadingUnixStreamServer(self):
@requires_forking
def test_ForkingUnixStreamServer(self):
with simple_subprocess(self):
self.run_server(ForkingUnixStreamServer,
self.run_server(socketserver.ForkingUnixStreamServer,
socketserver.StreamRequestHandler,
self.stream_examine)

Expand Down Expand Up @@ -247,7 +232,7 @@ def test_ThreadingUnixDatagramServer(self):
@requires_unix_sockets
@requires_forking
def test_ForkingUnixDatagramServer(self):
self.run_server(ForkingUnixDatagramServer,
self.run_server(socketserver.ForkingUnixDatagramServer,
socketserver.DatagramRequestHandler,
self.dgram_examine)

Expand Down