奇怪的 Linux 套接字协议行为

发布于 2024-12-03 23:01:17 字数 1509 浏览 0 评论 0原文

当使用 socket() 时,我对 Linux 上协议定义之间的差异有点困惑。我正在尝试使用 socket(PF_INET, SOCK_STREAM, proto) 监听 TCP 上的连接,其中 proto (在我看来)是有争议的,或者至少看起来很奇怪。

来自

...
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(7) 中介绍了您初始化 TCP 套接字,

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,如上所述。

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

  1. 为什么当我用 IPPROTO_TCP 替换所有协议参数时,在设置时会出现错误 92(“协议不可用”)超时,当协议 0 显然只是一个“虚拟”TCP 时?
  2. 为什么 socket() 需要它是否应该是流、数据报或原始套接字的信息,而该信息(总是?)从协议中隐式得知,反之亦然? (即 TCP 是流协议,UDP 是数据报协议,...)
  3. “虚拟 TCP”是什么意思?
  4. 什么是 hopopt,为什么它的协议号与“ip”相同?

非常感谢。

I'm a little confused about the difference between the definitions of protocols on Linux when using socket(). 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.

From <netinet/in.h>:

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

Agreed with by /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_socket = socket(AF_INET, SOCK_STREAM, 0);

which works absolutely fine, and certainly is a TCP socket. 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.

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?
  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? (i.e. TCP is a stream protocol, UDP is a datagram protocol, ...)
  3. What could be meant by "dummy TCP"?
  4. What is hopopt, and why does it have the same protocol number as 'ip'?

Many thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

如何视而不见 2024-12-10 23:01:17

将 0 作为 socket 的协议仅意味着您要使用 family/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

Giving 0 as protocol to socket just means that you want to use the default protocol for the family/socktype pair. In this case that is TCP, and thus you get the same result as with IPPROTO_TCP.

Your error is in the setsockopt call. 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. IPPROTO_TCP is another option level, but you can't combine that with SO_RCVTIMEO. It can only be used together with SOL_SOCKET.
The ones you use with IPPROTO_TCP are the ones listed in tcp(7), e.g. TCP_NODELAY.

我的黑色迷你裙 2024-12-10 23:01:17

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 可以以基于数据报或流的方式使用。因此套接字(AF_INET,IPPROTO_SCTP);会很含糊。对于数据报套接字,还有其他选择,UDP、DCCP、UDPlite。

套接字(AF_INET,SOCK_SEQPACKET,0);是另一个有趣的选择。它无法返回 TCP 套接字,TCP 不是基于数据包的。它无法返回 UDP 套接字,UDP 不保证顺序传送。但如果系统支持的话,SCTP 套接字就可以了。

我无法解释为什么有人评论“虚拟 TCP”,因为 linux netinet/in.h

hopopt 是 IPv6 HOP by hop 选项。在IPv6中,协议鉴别符字段也被用作扩展机制。在 IPv4 数据包中有一个协议字段,它是协议鉴别符,如果 IPv4 数据报携带 TCP,它将被设置为 IPPROTO_TCP。如果该 IPv4 数据包还携带一些附加信息(选项),则它们会通过其他机制进行编码。

IPv6 的做法有所不同,如果有扩展(选项),则该扩展会编码在协议字段中。因此,如果 IPv6 数据包需要逐跳选项,则将 IPPROTO_HOPOPTS 放置在协议字段中。实际的逐跳选项还有一个协议鉴别器,它指示下一个协议是什么 - 可能是 IPPROTO_TCP,或另一个选项。

socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); should work fine.

Passing 0 as the protocol just means, give me the default. Which on every system is TCP for stream sockets and UDP for datagram sockets, when dealing with IP. But socket() can be used for many other things bar giving you a TCP or UDP socket.

socket() is quite general in nature. socket(AF_INET, SOCK_STREAM, 0); just reads as; "give me a streaming socket within the IP protocol family". Passing 0 means you have no preferences over which protocol - though TCP is the obvious choice for any system. But theoretically, it could have given you e.g. an SCTP socket.

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.

For IP based protocols, SCTP can be used in a datagram based, or streaming fashion. Thus socket(AF_INET,IPPROTO_SCTP); would be ambiguous. And for datagram sockets, there's other choices as well, UDP, DCCP, UDPlite.

socket(AF_INET,SOCK_SEQPACKET,0); is another interesting choice. It cannot return a TCP socket, TCP is not packet based. It cannot return and UDP socket, UDP gives no guarantee of sequential delivery. But an SCTP socket would do, if the system supports it.

I have no explanation for why someone made the comment "dummy TCP" in that the linux netinet/in.h

hopopt is the IPv6 HOP by hop option. In IPv6, the protocol discriminator field is also used as an extension mechanism. 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. If that IPv4 packet also carries some additional info(options), they are coded by other mechanisms.

IPv6 does this differently, if there is an extension(option), that extension is coded in the protocol field. So if the IPv6 packet needs the hop-by-hop option, IPPROTO_HOPOPTS is placed in the protocol field. 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文