AF_INET6类型UDP套接字跨协议发送数据的sendto用法正确性问询
嘿,这个问题问得很到位,刚好涉及到IPv6套接字的跨协议兼容特性,我来给你梳理清楚:
直接传递AF_INET地址给AF_INET6套接字的sendto()
这个是可行的,前提是你的AF_INET6套接字没有启用IPV6_V6ONLY选项(多数主流操作系统默认是关闭这个选项的)。当你把AF_INET的sockaddr_in结构体传给sendto()时,操作系统会自动将IPv4地址映射为IPv6兼容地址(比如::ffff:192.168.1.1这种形式),然后完成发送。所以你贴的第一段代码是正确的,能正常工作。传递AF_INET6地址给AF_INET6套接字的sendto()
这个完全没问题,AF_INET6套接字本身就是为处理IPv6地址设计的,你贴的第二段代码是标准用法,肯定正确。使用sockaddr_storage的情况
这个做法不仅正确,还是推荐的通用写法。sockaddr_storage就是为统一存储不同类型的地址结构(AF_INET或AF_INET6等)设计的,它的大小足够容纳所有系统支持的地址类型。你的代码逻辑是对的:先将sockaddr_storage转换为对应的地址结构体(比如sockaddr_in),设置地址族及其他参数,然后在sendto()中转换为sockaddr*传入。不过有个小细节要注意:sendto()的最后一个参数应该传入实际地址结构的大小(比如AF_INET就传sizeof(struct sockaddr_in),AF_INET6传sizeof(struct sockaddr_in6)),而不是sockaddr_storage的大小。虽然很多系统能忽略多余的长度,但严格来说传递准确的长度更规范。
另外补充一点:如果你手动给AF_INET6套接字开启了IPV6_V6ONLY选项,那它就只能处理IPv6地址,无法再发送IPv4数据了,所以要确保这个选项处于关闭状态(默认就是关闭的)。
备注:内容来源于stack exchange,提问作者NickG

