简体   繁体   English

奇怪的Linux套接字协议行为

[英]Strange Linux socket protocols behaviour

I'm a little confused about the difference between the definitions of protocols on Linux when using socket() . 对于使用socket()时Linux上的协议定义之间的差异,我有些困惑。 I am attempting to listen for connections over TCP using socket(PF_INET, SOCK_STREAM, proto) , where proto is (in my mind) disputed, or at least seems odd. 我试图使用socket(PF_INET, SOCK_STREAM, proto)侦听TCP上的连接,在我看来, proto存在争议,或者至少看起来很奇怪。

From <netinet/in.h> : <netinet/in.h>

...
IPPROTO_IP = 0,    /* Dummy protocol for TCP.  */
...
IPPROTO_TCP = 6,       /* Transmission Control Protocol.  */
...

Agreed with by /etc/protocols : 同意/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
...

I learned from an online tutorial, and also from the man page tcp(7) that you initialise a TCP socket using 我从网上教程中学, 从该名男子页tcp(7)您在使用初始化TCP套接字

tcp_socket = socket(AF_INET, SOCK_STREAM, 0);

which works absolutely fine, and certainly is a TCP socket. 它绝对可以正常工作,并且肯定一个TCP套接字。 One thing about using the above arguments to initialise a socket is that the code 使用上述参数初始化套接字的一件事是该代码

struct timeval timeout = {1, 0};
setsockopt(tcp_socket, 0, SO_RCVTIMEO, &timeout, sizeof(timeout); // 1s timeout
// Exactly the same for SO_SNDTIMEO here

works absolutely fine, but not after replacing all protocol arguments (including in socket() ) with IPPROTO_TCP , as opposed to IPPROTO_IP which they have, as above. 精绝,但替换所有协议参数(包括后没有工作的socket()IPPROTO_TCP ,而不是IPPROTO_IP他们有,如上述。

So after experimenting with the difference, I've needed to ask a few searching questions: 因此,在尝试了差异之后,我需要问一些搜索问题:

  1. Why, when I replace all protocol arguments with IPPROTO_TCP , do I get error 92 ("Protocol not available") when setting timeouts, when protocol 0 is apparently just a 'dummy' TCP? 为什么当我用IPPROTO_TCP替换所有协议参数时,设置协议0显然只是一个“虚拟” TCP时,设置超时时会出现错误92(“协议不可用”)?
  2. Why does socket() require the information of whether it should be a stream, datagram or raw socket when that information is (always?) implicitly known from the protocol, and vice versa? 为什么从协议隐式知道(总是?) socket()应该是流,数据报还是原始套接字的信息,反之亦然? (ie TCP is a stream protocol, UDP is a datagram protocol, ...) (即,TCP是流协议,UDP是数据报协议,...)
  3. What could be meant by "dummy TCP"? “虚拟TCP”可能意味着什么?
  4. What is hopopt , and why does it have the same protocol number as 'ip'? 什么是hopopt ,为什么它的协议号与'ip'相同?

Many thanks. 非常感谢。

Giving 0 as protocol to socket just means that you want to use the default protocol for the family/socktype pair. socket提供0协议只是意味着您要为family / socktype对使用默认协议。 In this case that is TCP, and thus you get the same result as with IPPROTO_TCP . 在这种情况下,它是TCP,因此得到的结果与IPPROTO_TCP相同。

Your error is in the setsockopt call. 您的错误是在setsockopt调用中。 The correct one would be 正确的是

setsockopt(tcp_socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); // 1s timeout

the 0 there is not for protocol, but for option level. 0不是协议,而是选项级别。 IPPROTO_TCP is another option level, but you can't combine that with SO_RCVTIMEO . IPPROTO_TCP是另一个选项级别,但是您不能将其与SO_RCVTIMEO结合使用。 It can only be used together with SOL_SOCKET . 它只能与SOL_SOCKET一起使用。 The ones you use with IPPROTO_TCP are the ones listed in tcp(7), eg TCP_NODELAY . IPPROTO_TCP一起使用的是tcp(7)中列出的那些,例如TCP_NODELAY

socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); should work fine. 应该工作正常。

Passing 0 as the protocol just means, give me the default. 作为协议传递0只是意味着,请给我默认值。 Which on every system is TCP for stream sockets and UDP for datagram sockets, when dealing with IP. 当处理IP时,在每个系统上哪个是用于流套接字的TCP和用于数据报套接字的UDP。 But socket() can be used for many other things bar giving you a TCP or UDP socket. 但是socket()可以用于许多其他事情,而不会给您提供TCP或UDP套接字。

socket() is quite general in nature. socket()本质上是非常通用的。 socket(AF_INET, SOCK_STREAM, 0); just reads as; 读为 "give me a streaming socket within the IP protocol family". “给我IP协议系列中的流式套接字”。 Passing 0 means you have no preferences over which protocol - though TCP is the obvious choice for any system. 传递0表示您对哪种协议没有偏好-尽管TCP对于任何系统都是显而易见的选择。 But theoretically, it could have given you eg an SCTP socket. 但从理论上讲,它可以为您提供SCTP套接字。

Whether you want datagram or streaming sockets is not implicit for protocols. 协议隐含数据报或流套接字。 There are many more protocols bar IP based protocols, and many can be used in either datagram or streaming mode such as SCCP used in SS7 networks. 除了基于IP的协议外,还有更多协议,并且许多协议可以用于数据报或流模式,例如SS7网络中使用的SCCP。

For IP based protocols, SCTP can be used in a datagram based, or streaming fashion. 对于基于IP的协议,SCTP可以以基于数据报或流方式使用。 Thus socket(AF_INET,IPPROTO_SCTP); 因此套接字(AF_INET,IPPROTO_SCTP); would be ambiguous. 会模棱两可。 And for datagram sockets, there's other choices as well, UDP, DCCP, UDPlite. 对于数据报套接字,还有其他选择,UDP,DCCP,UDPlite。

socket(AF_INET,SOCK_SEQPACKET,0); 插座(AF_INET,SOCK_SEQPACKET,0); is another interesting choice. 是另一个有趣的选择。 It cannot return a TCP socket, TCP is not packet based. 它不能返回TCP套接字,TCP不是基于数据包的。 It cannot return and UDP socket, UDP gives no guarantee of sequential delivery. 它不能返回并且使用UDP套接字,UDP无法保证顺序传送。 But an SCTP socket would do, if the system supports it. 但是,如果系统支持,则SCTP套接字可以。

I have no explanation for why someone made the comment "dummy TCP" in that the linux netinet/in.h 我没有解释为什么有人在linux netinet / in.h中发表评论“ dummy TCP”

hopopt is the IPv6 HOP by hop option. hopopt是“按跳的IPv6 HOP”选项。 In IPv6, the protocol discriminator field is also used as an extension mechanism. 在IPv6中,协议鉴别符字段也用作扩展机制。 In IPv4 packets there is a protocol field which is the protocol discriminator, it'll be set to IPPROTO_TCP if that IPv4 datagram carries TCP. 在IPv4数据包中,有一个协议字段,它是协议标识符,如果该IPv4数据报带有TCP,则将其设置为IPPROTO_TCP。 If that IPv4 packet also carries some additional info(options), they are coded by other mechanisms. 如果该IPv4数据包还包含一些其他信息(选项),则它们将通过其他机制进行编码。

IPv6 does this differently, if there is an extension(option), that extension is coded in the protocol field. IPv6的操作与此不同,如果有扩展名(选项),则该扩展名将在协议字段中进行编码。 So if the IPv6 packet needs the hop-by-hop option, IPPROTO_HOPOPTS is placed in the protocol field. 因此,如果IPv6数据包需要逐跳选项,则将IPPROTO_HOPOPTS放在协议字段中。 The actual hop-by-hop option also have a protocol discriminator, which signals what the next protocol is - which might be IPPROTO_TCP, or yet another option. 实际的逐跳选项还具有协议区分符,该协议区分符指示下一个协议是什么-可能是IPPROTO_TCP或另一个选项。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM