我目前正在开发一个UDP套接字应用程序,需要添加支持,以便IPV4和IPV6连接可以向服务器发送数据包。
我希望有人能帮助我指明方向,因为我找到的大多数文档都不完整。如果您能指出Winsock和BSD套接字之间的任何区别,那将非常有帮助。
提前感谢您的帮助!
最好的方法是创建一个IPv6服务器套接字,还可以接受IPv4连接。为此,创建一个普通的IPv6套接字,关闭套接字选项IPV6_V6ONLY
,将其绑定到“任何”地址,并开始接收。 IPv4地址将以IPv4-mapped格式表示为IPv6地址。
系统之间的主要区别在于IPV6_V6ONLY
选项是否可用,以及默认情况下它是否被打开或关闭。在Linux上,默认情况下它被关闭(即允许双栈套接字而不需要setsockopt),而在大多数其他系统上它被打开。
此外,Windows XP上的IPv6堆栈不支持该选项。在这些情况下,您需要创建两个单独的服务器套接字,并将它们放入select中或多线程中。
套接字API受IETF RFC的管理,并且应该在所有平台上都相同,包括支持IPv6的Windows。
对于IPv4/IPv6应用程序,一切都关乎getaddrinfo()
和getnameinfo()
。 getaddrinfo
是一个天才-它查看客户端的DNS、端口名称和能力来解决“是否可以使用IPv4、IPv6或两者都到达特定目标”这个永恒的问题?如果您选择双栈路线,并希望它返回IPv4映射的IPv6地址,它也会做到。
它提供了一个直接的sockaddr *
结构,可以插入bind()
、recvfrom()
、sendto()
和socket()
的地址族……在许多情况下,这意味着没有混乱的sockaddr_in(6)
结构要填写和处理。
对于UDP实现,我会谨慎设置双栈套接字,或者更普遍地绑定到所有接口(INADDR_ANY
)。经典问题是,当地址没有锁定(参见bind()
)到特定接口并且系统具有多个接口请求时,响应可能从不同的地址传输,针对具有身份验证要求的应用程序协议可能会产生混淆。
对于不会出现这种问题的UDP实现,或者TCP,双栈套接字可以节省大量时间,用于启用IPv*系统。必须注意,在不绝对必要的情况下不要完全依赖双栈,因为部署了不支持双栈套接字的IPv6堆栈的合理平台(旧版Linux、BSD、Windows 2003)并不少见。
我一直在Windows下测试这个,实际上它似乎确实存在安全问题。如果你绑定到回环地址,那么IPv6套接字将正确绑定到[::1],但映射的IPv4套接字将绑定到INADDR_ANY,因此你的(应该是)仅限于本地的应用程序实际上会暴露给全世界。
hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_PASSIVE;
...
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
host_port = "4950"; // whatever
// All of these work.
host_ip = "127.0.0.1"; // Pure IPv4 address
host_ip = "::ffff:127.0.0.1"; // IPv4 address expressed as IPv6
host_ip = "::1"; // Pure IPv6 address
host_ip = "localhost"; // Domain name
int rv = getaddrinfo(host_ip, host_port, &hints, &result);
...
IPV6_V6ONLY
默认情况下是关闭的(我已经验证过了)。即使man ipv6
也指定了:此标志的默认值由文件/proc/sys/net/ipv6/bindv6only
的内容定义。该文件的默认值为0(false)。 我认为你的帖子可能是指旧版的 Linux Debian 发行版。 - patryk.beza