我在查找关于第三个参数设置区别的文档时遇到些困难,我知道TCP和UDP之间的差异以及IP位于堆栈中的哪一层,但是无论我将UDP代码设置为“ IPPROTO_IP”还是“ IPPROTO_UDP”,它都能正常工作。
Linux中socket()
的文档分散在各种手册页中,包括指定您必须使用0
或IPPROTO_UDP
来进行UDP通信以及使用0
或IPPROTO_TCP
来进行TCP通信的ip(7)
。当您使用0
时,它恰好是IPPROTO_IP
的值,用于SOCK_DGRAM
的是UDP,用于SOCK_STREAM
的是TCP。
我认为创建UDP或TCP IPv4套接字对象的简洁方法如下:
int sock_udp = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
int sock_tcp = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
之所以这样做,是因为明确比含蓄更好。在这种特定情况下,使用 0
或者更糟糕的 IPPROTO_IP
作为第三个参数并没有任何好处。
此外,想象一下使用可以同时进行流和数据报的协议,比如 sctp。通过始终指定 socktype 和 protocol,您可以避免任何歧义。
来自Linux手册页中的socket(2)
,来自man-pages
5.08:
通常,在给定协议族中支持特定套接字类型的只有一个协议存在,此时可以将协议指定为0。但是,可能存在许多协议,此时必须以这种方式指定特定协议。
IPPROTO_IP
只是IPPROTO_
*系列中的常规占位符常量,在socket API中的值为0
,自早期以来一直如此。
当然,为了前向兼容性,如果将来为协议族添加更多的套接字类型,这可能会破坏UDP/TCP的0
或更改其行为,最好查找所需协议的特定协议值并使用它,而不是使用0
或IPPROTO_IP
。
IPPROTO_
*头值在不同的上下文中具有多种用途:除了在套接字API和其实现代码内部中用作参数值以标识协议之外,它们还用作IP数据包本身中IP协议字段的值。这些IP协议值,或者在IANA术语中的协议号码,本身具有另一个目的,即在IPv6中标识不同的扩展头类型。这就是为什么0
也是IPPROTO_HOPOPTS
,它是IPv6跳跃选项扩展头的标识符。
SOCK_DGRAM
和SOCK_STREAM
?以及何时需要IPPROTO_UDP
? - Gabriel Staples