我对使用socket()
时Linux上的协议定义之间的区别感到有些困惑。我正在尝试使用socket(PF_INET, SOCK_STREAM, proto)
来监听TCP上的连接,其中proto
(在我看来)是有争议的,或者至少看起来很奇怪。
来自<netinet/in.h>
:
...
IPPROTO_IP = 0, /* Dummy protocol for TCP. */
...
IPPROTO_TCP = 6, /* Transmission Control Protocol. */
...
同意/etc/protocols
:
ip 0 IP # internet protocol, pseudo protocol number
hopopt 0 HOPOPT # hop-by-hop options for ipv6
...
tcp 6 TCP # transmission control protocol
...
我从在线教程中学到了,并且使用
初始化TCP套接字的手册页tcp(7)
中的
tcp_socket = socket(AF_INET, SOCK_STREAM, 0);
绝对正常,当然 是一个TCP套接字。使用上述参数初始化套接字的一件事是代码
struct timeval timeout = {1, 0};
setsockopt(tcp_socket, 0, SO_RCVTIMEO, &timeout, sizeof(timeout); // 1s timeout
// Exactly the same for SO_SNDTIMEO here
在使用socket()
替换所有协议参数(包括IPPROTO_TCP
中)后,不,而不是IPPROTO_IP
,而不是IPPROTO_TCP
。上方。
因此,在尝试了差异后,我需要提出一些搜索问题:
socket()
替换所有协议参数时,在设置超时时是否会收到错误92(“协议不可用”),协议0显然只是一个“虚拟”TCP?hopopt
需要在协议中隐含地知道该信息(总是?)时是否应该是流,数据报或原始套接字的信息,反之亦然? (即TCP是流协议,UDP是数据报协议,......)非常感谢。
答案 0 :(得分:3)
将0作为协议赋予socket
只意味着您要使用系列/ socktype对的默认协议。在这种情况下,这是TCP,因此您获得与IPPROTO_TCP
相同的结果。
您的错误发生在setsockopt调用中。正确的是
setsockopt(tcp_socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); // 1s timeout
0表示没有协议,但是对于选项级别。 IPPROTO_TCP
是另一个选项级别,但您无法将其与SO_RCVTIMEO
结合使用。它只能与SOL_SOCKET
一起使用。
与IPPROTO_TCP
一起使用的是tcp(7)中列出的那些,例如TCP_NODELAY
。
答案 1 :(得分:2)
socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
应该可以正常工作。
传递0作为协议只是意味着,给我默认。在处理IP时,每个系统上的哪个系统都是用于流套接字的TCP和用于数据报套接字的UDP。但是socket()可以用于许多其他东西吧,为你提供TCP或UDP套接字。
socket()本质上很通用。 socket(AF_INET, SOCK_STREAM, 0);
只读为; “在IP协议系列中给我一个流式套接字”。传递0表示您对哪个协议没有偏好 - 尽管TCP是任何系统的明显选择。但理论上,它可以给你,例如一个SCTP套接字。
对于协议,是否需要数据报或流套接字 。基于IP的协议还有许多协议,并且许多协议可用于数据报或流模式,例如SS7网络中使用的SCCP。
对于基于IP的协议,SCTP可以基于数据报或流式方式使用。因此socket(AF_INET,IPPROTO_SCTP);会很暧昧。对于数据报套接字,还有其他选择,UDP,DCCP,UDPlite。
插座(AF_INET,SOCK_SEQPACKET,0);是另一个有趣的选择。它不能返回TCP套接字,TCP不是基于数据包的。它无法返回和UDP套接字,UDP无法保证顺序传送。但是,如果系统支持,SCTP套接字就可以。
我没有解释为什么有人在linux netinet / in.h中发表评论“虚拟TCP”
hopopt是IPv6 HOP逐跳选项。在IPv6中,协议鉴别器字段也用作扩展机制。在IPv4数据包中有一个协议字段,它是协议鉴别符,如果IPv4数据报携带TCP,它将被设置为IPPROTO_TCP。如果该IPv4数据包还带有一些额外的信息(选项),则它们由其他机制编码。
IPv6以不同的方式执行此操作,如果存在扩展名(选项),则该扩展名将在协议字段中进行编码。因此,如果IPv6数据包需要逐跳选项,则IPPROTO_HOPOPTS将放置在协议字段中。实际的逐跳选项还有一个协议鉴别器,它可以指示下一个协议是什么 - 可能是IPPROTO_TCP,或者是另一种选择。