By searching for 'python dual-stack', I found https://bugs.python.org/issue25667 where someone mentions that this was already resolved in https://bugs.python.org/issue17561. In the latter issue, one of the last messages helpfully mentions what the implemented solution is:
# IPv4 only
>>> socket.create_server(addr)
# IPv6 only
>>> socket.create_server(addr, family=socket.AF_INET6)
# IPv4 IPv6
>>> socket.create_server(addr, family=socket.AF_INET6, dualstack_ipv6=True)
However, I was looking for a generic solution. Or rather, I was looking for UDP but figured that, because this is on the IP layer, any solution would be generic. It turns out that create_server()
is TCP-only.
Binding to both v4 and v6 manually means I cannot just call recvfrom()
and let it block until a packet comes in, because then a v6 packet might be queued while it's blocking on the v4 recvfrom
call or vice versa. So I guess I need to use threading?
What is the best way to make a dual-stack UDP server in python 3.x? For me, a Linux solution would be sufficient, but of course platform-independent answers are even better.
Basically, how to write this in dual-stack:
import socket
server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_socket.bind(('0.0.0.0', 53))
while True:
message, address = server_socket.recvfrom(1400)
CodePudding user response:
At least under Linux, creating an IPv6 socket listens for both IPv6 and IPv4 connections. That is, given this code:
import socket
s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
s.bind(('::', 9090))
while True:
message, address = s.recvfrom(1024)
print(address, "says: ", message.decode())
I can connect using IPv4:
echo hello world | nc -u 127.0.0.1 9090
Which results in:
('::ffff:127.0.0.1', 36694, 0, 0) says: hello world
Or I can connect using IPv6:
echo hello world | nc -u ::1 9090
Which results in:
('::1', 51880, 0, 0) says: hello world