SOCK_DGRAM 和 SOCK_STREAM 是啥?

Posted

技术标签:

【中文标题】SOCK_DGRAM 和 SOCK_STREAM 是啥?【英文标题】:What is SOCK_DGRAM and SOCK_STREAM?SOCK_DGRAM 和 SOCK_STREAM 是什么? 【发布时间】:2011-08-14 12:19:10 【问题描述】:

我刚刚遇到了一个奇怪的事情,我看到应用程序默认情况下它们使用SOCK_STREAM 函数。为什么会这样?这是SOCK_STREAM 只是创建多个流吗?或者它是可用于创建 TCP 流的标准 SOCK_STREAM 函数?

我认为 tsunami 是基于 UDP 的,但仍然具有一些类似于 TCP 的功能,例如TCP 公平、友好等。

有人可以解释一下这个问题吗?我对此感到非常困惑。

【问题讨论】:

它们不是函数,它们是根据其文档提供给socket() 系统调用的清单常量。 【参考方案1】:

TCP 几乎总是使用SOCK_STREAM 而UDP 使用SOCK_DGRAM

TCP (SOCK_STREAM) 是一种基于连接的协议。连接已建立,并且双方进行对话,直到连接被其中一方或网络错误终止。

UDP (SOCK_DGRAM) 是一种基于数据报的协议。您发送一个数据报并得到一个回复​​,然后连接终止。

如果您发送多个数据包,TCP 承诺按顺序传送它们。 UDP没有,所以接收者需要检查它们,如果命令 很重要。

如果 TCP 数据包丢失,发送者可以知道。 UDP 则不然。

UDP 数据报的大小是有限的,从内存我认为是 512 字节。 TCP 可以发送比这更大的块。

TCP 更健壮一些,并且进行更多检查。 UDP是一个阴影 重量更轻(计算机和网络压力更小)。

选择适合您与其他计算机交互方式的协议。

【讨论】:

我使用 EMBOS 的 IP 堆栈。我创建了一个 SOCK_DGRAM 类型的套接字。但是当我收到一个 UDP 数据包时,只有第一次调用 select 函数......在这种情况下是否与套接字类型有关? @GinuJacob - 我对 EMBOS 一无所知。创建一个新问题并选择标签(例如“EMBOS”),以吸引具有合适技能的人来帮助您。 UDP/SOCK_DGRAM 是一种基于数据报的协议,不涉及任何连接。您发送任意数量的数据报并接收任意数量的数据报。这是一项“不可靠的服务”。 TCP/SOCK_STREAM 是一种“可靠”或“已确认”的服务,因为数据包按顺序传送,或者连接终止。保证是如果数据可能尚未交付,您会收到通知。 @JeffLearman 实际上并非如此,UDP 仅被限制(作为协议)为 2^16 字节。无论 MTU 如何,您都可以使用 IP 分片发送非常大的 UDP 数据包,内核将为您重新组装它们【参考方案2】:

Berkley Sockets API 背后的一个想法是它可以使用不同的 protocol families - 而不仅仅是互联网协议 (IP)。但相反,您有一个 API 可以处理各种“地址族”,例如:

Internet 协议版本 4 (IPv4):AF_INET IPX/SPX:AF_IPX AppleTalk:AF_APPLETALK NetBiosAF_NETBIOS Internet 协议版本 6 (IPv6):AF_INET6 红外数据协会 (IrDA):AF_IRDA 蓝牙:AF_BTH

每个协议族通常都有一些关于如何在套接字上处理数据的类似概念:

顺序的、可靠的、双向的、基于连接的、字节流:SOCK_STREAM (IP 人称之为 TCP) 无连接、不可靠的数据报:SOCK_DGRAM (IP 人会称之为 UDP)

不同的地址族对这些基本概念有不同的称谓:

╔═══════════╦══════════════════════════╗
║           ║       Socket Type        ║
║ Address   ╟────────────┬─────────────╢
║ Family    ║ SOCK_DGRAM │ SOCK_STREAM ║ 
╠═══════════╬════════════╪═════════════╣
║ IPX/SPX   ║ SPX        │ IPX         ║
║ NetBIOS   ║ NetBIOS    │ n/a         ║
║ IPv4      ║ UDP        │ TCP         ║
║ AppleTalk ║ DDP        │ ADSP        ║
║ IPv6      ║ UDP        │ TCP         ║
║ IrDA      ║ IrLMP      │ IrTTP       ║
║ Bluetooth ║ ?          │ RFCOMM      ║
╚═══════════╩════════════╧═════════════╝

重点是:

如果您想要可靠的、双向的、基于连接的、顺序的、字节流 您使用 "SOCK_STREAM" 要求它sockets API 会担心你需要 TCP

同样,如果我在红外线上创建一个套接字(IrDA,AF_IRDA):

我不知道 IrDA 中的哪种协议是可靠的、有序的和基于连接的 我只知道我想要一些东西,它是可靠的、顺序的和基于连接的

所以你说:

socket(AF_IRDA, SOCK_STREAM, 0);

Sockets 会帮我解决的。

奖金

最初只有两个协议选项:

无连接、不可靠的数据报 (SOCK_DGRAM) 基于连接、可靠、有序、双向 (SOCK_STREAM)

后来添加了其他协议选择:

可靠的消息数据报(SOCK_RDM - “可靠的数据报多播” - 已过时;不要在新程序中使用) 基于数据报的伪流序列数据包 (SOCK_SEQPACKET)
╔═══════════╦══════════════════════════════════════════════════════╗
║           ║                      Socket Type                     ║
║ Address   ╟────────────┬─────────────┬──────────┬────────────────╢
║ Family    ║ SOCK_DGRAM │ SOCK_STREAM │ SOCK_RDM │ SOCK_SEQPACKET ║ 
╠═══════════╬════════════╪═════════════╪══════════╪════════════════╣
║ IPX/SPX   ║ SPX        │ IPX         │ ?        │ ?              ║
║ NetBIOS   ║ NetBIOS    │ n/a         │ ?        │ ?              ║
║ IPv4      ║ UDP        │ TCP         │ ?        │ SCTP           ║
║ AppleTalk ║ DDP        │ ADSP        │ ?        │ ?              ║
║ IPv6      ║ UDP        │ TCP         │ ?        │ SCTP           ║
║ IrDA      ║ IrLMP      │ IrTTP       │ ?        │ ?              ║
║ Bluetooth ║ ?          │ RFCOMM      │ ?        │ ?              ║
╚═══════════╩════════════╧═════════════╧══════════╧════════════════╝

不保证任何给定的地址族都支持此类协议选择;但有些人会这样做。

奖金奖金聊天

希望现在您明白为什么在调用中传递IPPROTO_TCP 协议以创建套接字是多余的:

socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // passing IPPROTO_TCP is redundant
socket(AF_INET, SOCK_STREAM, 0);           // better

你已经说过你想要SOCK_STREAM。你不需要在它上面强制TCP。以同样的方式调用是多余的:

socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); //passing IPPROTO_UDP is redundant
socket(AF_INET, SOCK_DGRAM, 0);           // better

tl;dr: 这是一种请求 TCP 或 UDP 的独立于协议的方式。但由于地球上没有人再使用 AppleTalk、IPX/SPX、IrDA、蓝牙、NetBIOS,它大多是退化的。

【讨论】:

我认为这不应该是最被接受的答案 @ArkestMust 您的评论缺乏相关性。 TCP 遍及全球。蓝牙跨越约 100 英尺。无论如何,蓝牙是一个媒体层,而 TCP 是一个会话层协议。根本没有可比性。【参考方案3】:

更新:我的回答似乎不再相关,但最初的问题是指 UDT,它是一种建立在 UDP 之上的面向连接的协议。更多信息在这里:http://en.wikipedia.org/wiki/UDP-based_Data_Transfer_Protocol


UDT 似乎提供了模仿经典 BSD 套接字 API 的 API,因此它可以用作面向流和数据报的应用程序的直接替代品。检查例如sendmsgrecvmsg - 如果在使用 SOCK_STREAM 创建的套接字上使用它们都会抛出异常,并且所有面向流的 API 也会对使用 SOCK_DGRAM 创建的套接字抛出异常。

如果是SOCK_DGRAM,它会执行一些额外的处理,但是在这种情况下它不会简单地透明地包装 UDP 套接字 - 据我在快速查看后理解代码(我不熟悉 UDT 内部或协议规范)。阅读technical papers 会有很大帮助。

该库始终将其底层的“真实”套接字创建为数据报之一(检查 channel.cpp,CChannel::open)。

【讨论】:

【参考方案4】:

TCP 使用 SOCK_STREAM,UDP 使用 SOCK_DGRAM。

【讨论】:

所以你刚刚从第一个答案中复制了第一行。更具体地了解 OP 提出的问题。 @Xenikh 不,他没有。他正确地省略了“几乎总是”这个荒谬的限定词。

以上是关于SOCK_DGRAM 和 SOCK_STREAM 是啥?的主要内容,如果未能解决你的问题,请参考以下文章

SOCK_DGRAM 和 SOCK_STREAM 在上下文 AF_UNIX 套接字中的用途是啥?

SOCK_STREAM & SOCK_DGRAM

流式套接字(SOCK_STREAM),数据报套接字 (SOCK_DGRAM) 的比较

Linux网络编程原始套接字能干什么?

socket

重温网络编程——协议