# IPv6 in socketserver

**URL:** <https://discuss.python.org/t/ipv6-in-socketserver/79551>\
**Category:** Ideas\
**Created:** [February 5, 2025, 8:13am UTC](https://discuss.python.org/t/ipv6-in-socketserver/79551 "2025-02-05T08:13:01Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![AEErshov](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/aeershov/32/25709_2.png) [@AEErshov](https://discuss.python.org/u/AEErshov)\
**Post date:** [February 5, 2025, 8:13am UTC](https://discuss.python.org/t/ipv6-in-socketserver/79551/1 "2025-02-05T08:13:01Z")

</div>

IPv6 is currently widely used. In socketserver library there is no IPv6 servers. Maybe we need IPv6 variant of all servers, something like this:

```python
class TCP6Server(TCPServer):
    address_family = socket.AF_INET6

```

and so on for other classes?

---

<div class="post-metadata">

**Author:** ![juancer](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/juancer/32/26511_2.png) [@juancer](https://discuss.python.org/u/juancer)\
**Post date:** [February 5, 2025, 9:28am UTC](https://discuss.python.org/t/ipv6-in-socketserver/79551/2 "2025-02-05T09:28:43Z")

</div>

But as you state, `socketserver`-based servers already support IPv6 with minimal changes.

You can even modify an existing server instance dynamically:

```python
server = socketserver.TCPServer(("::", 8000), MyHandler)
server.address_family = socket.AF_INET6

```

---

<div class="post-metadata">

**Author:** ![AEErshov](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/aeershov/32/25709_2.png) [@AEErshov](https://discuss.python.org/u/AEErshov)\
**Post date:** [February 6, 2025, 2:10am UTC](https://discuss.python.org/t/ipv6-in-socketserver/79551/3 "2025-02-06T02:10:54Z")

</div>

That’s right, but the same can be said about `UnixStreamServer` and `UnixDatagramServer`. We can easy create own, but we have UNIX servers in sdtlib.

---

<div class="post-metadata">

**Author:** ![juancer](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/juancer/32/26511_2.png) [@juancer](https://discuss.python.org/u/juancer)\
**Post date:** [February 6, 2025, 9:07am UTC](https://discuss.python.org/t/ipv6-in-socketserver/79551/4 "2025-02-06T09:07:54Z")

</div>

So, you suggest duplicating all server classes?

- `class socketserver.TCPServer(server_address, RequestHandlerClass, bind_and_activate=True )`
- `class socketserver.UDPServer(server_address, RequestHandlerClass, bind_and_activate=True)`
- `class socketserver.UnixStreamServer(server_address, RequestHandlerClass, bind_and_activate=True)`
- `class socketserver.UnixDatagramServer(server_address, RequestHandlerClass, bind_and_activate=True)`

Another solution could be to modify the `BaseServer` class to accept `address_family` and modify `TCPServer` and `UDPServer` to pass `address_family`.

Then if the user wants to use IPv6, the server declaration would look like `server = socketserver.TCPServer(("::", 9999), MyHandler, address_family=socket.AF_INET6)`.

The default could be set to `address_family=socket.AF_INET` to ensure backwards compatibility.

What do you think?

---

<div class="post-metadata">

**Author:** ![AEErshov](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/aeershov/32/25709_2.png) [@AEErshov](https://discuss.python.org/u/AEErshov)\
**Post date:** [February 7, 2025, 7:24am UTC](https://discuss.python.org/t/ipv6-in-socketserver/79551/5 "2025-02-07T07:24:46Z")

</div>

Let me explain.

| | `SOCK_STREAM` | `SOCK_DGRAM` |
| --- | --- | --- |
| **`AF_INET`** | `TCPServer` | `UDPServer` |
| \*_`AF_UNIX*`_ | `UnixStreamServer` | `UnixDatagramServer` |
| **`AF_INET6`** | _`TCP6Server`_ | _`UDP6Server`_ |

Classes on first 2 lines already exists. I sugest to create classes on third line (indicated _italic_). Of course in this case we should create `ForkingTCP6Server`, `ForkingUDP6Server`, `ThreadingTCP6Server` and `ThreadingUDP6Server` too.

You solution is very nice but there is small problem with backwards compatibility. Current code assume that `address_family` is a class variable. For example:

```python
class MyServer(socketserver.TCPServer):
   @classmethod
   def my_method(cls):
       print(cls.address_family)

```

Maybe this fact is not so important.

---

<div class="post-metadata">

**Author:** ![Rosuav](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/rosuav/32/3429_2.png) [@Rosuav](https://discuss.python.org/u/Rosuav)\
**Post date:** [February 7, 2025, 9:02am UTC](https://discuss.python.org/t/ipv6-in-socketserver/79551/6 "2025-02-07T09:02:28Z")

</div>

> [@AEErshov](#):
>
> You solution is very nice but there is small problem with backwards compatibility. Current code assume that `address_family` is a class variable. For example:
> 
> ```python
> class MyServer(socketserver.TCPServer):
> @classmethod
> def my_method(cls):
> print(cls.address_family)
> 
> ```
> 
> Maybe this fact is not so important.

IMO it would be ideal if the class could just figure out the address family from the address. Is there code that relies on this? If so, maybe address\_family could become a property. If, instead, it’s using `self.address_family`, then it’s easy; and the base server currently does exactly that.

---

<div class="post-metadata">

**Author:** ![xitop](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/xitop/32/13242_2.png) [@xitop](https://discuss.python.org/u/xitop)\
**Post date:** [February 7, 2025, 12:35pm UTC](https://discuss.python.org/t/ipv6-in-socketserver/79551/7 "2025-02-07T12:35:12Z")

</div>

Somehow related to the IPv6 discussion - a parameter to control the dual-stack option (at the low-level it’s the `IPV6_V6ONLY` socket option) as in the `socket.create_server` is missing in the socketserver.

---

<div class="post-metadata">

**Author:** ![picnixz](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/picnixz/32/12660_2.png) [@picnixz](https://discuss.python.org/u/picnixz)\
**Post date:** [February 8, 2025, 12:14pm UTC](https://discuss.python.org/t/ipv6-in-socketserver/79551/8 "2025-02-08T12:14:02Z")

</div>

Overall, the exposed classes were initially added in 1995, the same year IPv6 was proposed (standardized in 1998 in RFC 2460, and then updated in 2017 in RFC 8200). RFC 2460 and 8200 are both in the standard tracks, meaning that they are well-established RFCs that we can rely on.

Now that we are seeing more and more IPv6 usages in the wild, I think it would make sense to propose that in the standard library. We already have simple classes that just override the `address_family`, so I guess we can also add newest ones as well.

OTOH, the code duplication may look a bit ugly but we might also generate the classes dynamically instead. Or we could make a helper that creates an instance of a TCP server with the correct address family given an address (namely an alternative constructor given as a function) [something similar to `socket.create_server`, but that wouldn’t create a socket object, but really a socketserver object].

@guido You’re the main contributor to that module (you essentially wrote it 30 years ago and it hasn’t changed much since then). Do you think it makes sense to create a new interface for IPv6 or do you think we should just stick to TCP servers with a default `AF_INET` family? (cc @gpshead as the socket expert as well) Note that the docstring of the module says:

> This module tries to capture the various aspects of defining a server:
> 
> For socket-based servers:
> 
> - address family:
> - AF\_INET{,6}: IP (Internet Protocol) sockets (default)
> - AF\_UNIX: Unix domain sockets
> - others, e.g. AF\_DECNET are conceivable (see \<socket.h\>)

So one could say that the `AF_INET6` construction is missing as it’s being highlighted in the module docstring (I assume that anything else not exposed is being part of “others” and that we don’t need to bother about niche cases). WDYT?

---

<div class="post-metadata">

**Author:** ![gpshead](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/gpshead/32/54_2.png) [@gpshead](https://discuss.python.org/u/gpshead)\
**Post date:** [February 8, 2025, 6:17pm UTC](https://discuss.python.org/t/ipv6-in-socketserver/79551/9 "2025-02-08T18:17:31Z")

</div>

[This specific comment](https://github.com/python/cpython/issues/64414#issuecomment-1093641878) from Paul Marks in feature request GH-64414 which is basically what this discussion is about is a good summary.

Sure, we _could_ add IPv6-only server classes with a 6 in the name for TCP and UDP. But that doesn’t provide much value. Anyone can already get that today by writing two lines of code to just subclass and override `address_family = socket.AF_INET6`. It’s more of a documentation issue for that feature.

I left a more detailed comment on the issue.

---

<div class="post-metadata">

**Author:** ![guido](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/guido/32/21_2.png) [@guido](https://discuss.python.org/u/guido)\
**Post date:** [February 8, 2025, 8:21pm UTC](https://discuss.python.org/t/ipv6-in-socketserver/79551/10 "2025-02-08T20:21:27Z")

</div>

This code is antiquated and I’m not sure new projects should even consider using it, for all the reasons brought up in the GitHub issue Greg pointed to.

It does “support” IPv6 if you simply subclass TCPServer or UDPServer, overriding the `address_family` class attribute, literally just like the UNIX variants do.

It’s tempting to just add those (and the corresponding threading and forking variants) to the module and be done. I’d be okay with that. I’d also be okay if we declared the module not worth updating, ~~in which case we should probably (if it isn’t there already) add something to the docs explaining (a) that you can do that easily yourself, and (b) that this doesn’t help much unless you live in an IPv6-only world, because of widespread conventions and assumptions in a world where IPv6 and IPv4 have to live together~~.

I don’t think it’s a good idea to add any cleverness related to the hybrid world (i.e., the real world) here. Instead, that ought to go in some new module, possibly something 3rd party.

**EDIT:** Greg already merged a PR that adds exactly what I suggested to the docs.
