奇怪的Linux套接字协议行为

时间:2011-09-08 10:37:44

标签: c linux sockets protocols

我对使用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。上方。

因此,在尝试了差异后,我需要提出一些搜索问题:

  1. 为什么当我用socket()替换所有协议参数时,在设置超时时是否会收到错误92(“协议不可用”),协议0显然只是一个“虚拟”TCP?
  2. 为什么hopopt需要在协议中隐含地知道该信息(总是?)时是否应该是流,数据报或原始套接字的信息,反之亦然? (即TCP是流协议,UDP是数据报协议,......)
  3. “虚拟TCP”是什么意思?
  4. 什么是{{1}},为什么它的协议号与'ip'相同?
  5. 非常感谢。

2 个答案:

答案 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,或者是另一种选择。