什么是SOCK_DGRAM和SOCK_STREAM?

发布于 2024-11-03 23:27:59 字数 215 浏览 1 评论 0原文

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

我认为tsunami是基于UDP的,但仍然具有一些像TCP一样的特性,例如TCP公平性、友好性等。

有人可以解释一下这个问题吗?我对此完全困惑。

I just came across this strange thing I got to see application is that by default they use SOCK_STREAM function. Why is it so? Is this SOCK_STREAM just creating multiple streams? Or is it the standard SOCK_STREAM function available for creating TCP stream(s)?

I thought tsunami is based on UDP, but still having some features like that of TCP, e.g. TCP fairness, friendlyness, etc.

Could somebody please shed some light on this issue? I am totally confused over this.

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

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

发布评论

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

评论(4

乖乖 2024-11-10 23:27:59

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

TCP (SOCK_STREAM) 是一种基于连接的协议。连接建立后,两方进行对话,直到连接被一方或因网络错误终止。

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

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

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

  • UDP数据报的大小是有限的,凭记忆我认为是512
    字节。 TCP 可以发送比这大得多的块。

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

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

TCP almost always uses SOCK_STREAM and UDP uses SOCK_DGRAM.

TCP (SOCK_STREAM) is a connection-based protocol. The connection is established and the two parties have a conversation until the connection is terminated by one of the parties or by a network error.

UDP (SOCK_DGRAM) is a datagram-based protocol. You send one datagram and get one reply and then the connection terminates.

  • If you send multiple packets, TCP promises to deliver them in order.
    UDP does not, so the receiver needs to check them, if the order
    matters.

  • If a TCP packet is lost, the sender can tell. Not so for UDP.

  • UDP datagrams are limited in size, from memory I think it is 512
    bytes. TCP can send much bigger lumps than that.

  • TCP is a bit more robust and makes more checks. UDP is a shade
    lighter weight (less computer and network stress).

Choose the protocol appropriate for how you want to interact with the other computer.

自此以后,行同陌路 2024-11-10 23:27:59

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

  • Internet 协议版本 4 (IPv4):AF_INET
  • IPX/SPX:AF_IPX< /code>
  • AppleTalk:AF_APPLETALK
  • NetBIOS:AF_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”请求它
  • ,并且套接字 API将担心弄清楚您想要TCP

类似地,如果我正在创建一个套接字红外线(IrDA,AF_IRDA):

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

所以你说:

socket(AF_IRDA, SOCK_STREAM, 0);

套接字会为我解决这个问题。

Bonus

最初只有两个协议选项:

  • 无连接、不可靠、数据报 (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      │ ?        │ ?              ║
╚═══════════╩════════════╧═════════════╧══════════╧════════════════╝

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

Bonus Bonus Chatter

希望您现在明白为什么在调用中传递 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,所以它基本上已经退化了。

One of the ideas behind the Berkley Sockets API was that it could use different protocol families - not just the Internet Protocol (IP). Instead you had one API that could handle all kinds of "address families", e.g.:

  • Internet Protocol version 4 (IPv4): AF_INET
  • IPX/SPX: AF_IPX
  • AppleTalk: AF_APPLETALK
  • NetBIOS: AF_NETBIOS
  • Internet Protocol version 6 (IPv6): AF_INET6
  • Infrared Data Association (IrDA): AF_IRDA
  • Bluetooth: AF_BTH

Each protocol family generally has a few similar concepts of how data will be handled on a socket:

  • sequenced, reliable, two-way, connection-based, byte-streams: SOCK_STREAM (what an IP person would call TCP)
  • connectionless, unreliable, datagrams: SOCK_DGRAM (what an IP person would call UDP)

Different address families have different terms for these basic concepts:

╔═══════════╦══════════════════════════╗
║           ║       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      ║
╚═══════════╩════════════╧═════════════╝

The point is:

  • If you want reliable, two-way, connection-based, sequenced, byte-streams
  • you ask for it using "SOCK_STREAM"
  • and the sockets API will worry about figuring out that you want TCP

Similarly, if i were creating a socket over Infrared (IrDA, AF_IRDA):

  • i have no idea what protocol in IrDA is reliable, sequenced, and connection-based
  • all i know is that i want something that is reliable, sequence, and connection-based

So you say:

socket(AF_IRDA, SOCK_STREAM, 0);

And Sockets will figure it out for me.

Bonus

Originally there was only the two protocol options:

  • connectionless, unreliable, datagrams (SOCK_DGRAM)
  • connection-based, reliable, sequenced, two-way (SOCK_STREAM)

Later other protocol choices were added:

  • a reliable message datagram (SOCK_RDM - "Reliable Datagram Multicast" - obsolete; do not use in new programs)
  • pseudo-stream sequenced packets based on datagrams (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      │ ?        │ ?              ║
╚═══════════╩════════════╧═════════════╧══════════╧════════════════╝

It's not guaranteed that any given address family will support such protocol choices; but some do.

Bonus Bonus Chatter

Hopefully now you see why it is redundant to pass IPPROTO_TCP protocol in your call to create a socket:

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

You already said you wanted a SOCK_STREAM. You don't need to force TCP on top of it. In the same way it's redundant to call:

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

tl;dr: It's a protocol-independent way of asking for TCP or UDP. But since nobody on the planet uses AppleTalk, IPX/SPX, IrDA, Bluetooth, NetBIOS anymore, it's mostly vestigial.

楠木可依 2024-11-10 23:27:59

更新:我的回答似乎不再相关,但最初的问题提到了 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 内部结构或协议规范)。阅读技术论文会有很大帮助。

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

Update: my answer seems no more relevant, but the original question referred to UDT, which is a connection-oriented protocol built on top of UDP. More info here: http://en.wikipedia.org/wiki/UDP-based_Data_Transfer_Protocol


UDT appears to provide API which mimics classic BSD sockets API, so it can be used as a drop-in replacement, for both stream and datagram oriented applications. Check e.g. sendmsg and recvmsg - both throw an exception if used on a socket created with SOCK_STREAM, and all the stream oriented APIs throw an exception for socket created with SOCK_DGRAM as well.

In case of SOCK_DGRAM it perform some extra processing however, it doesn't simply wrap the UDP socket transparently in such case - as far as I understand the code after a quick review (I'm not familiar with UDT internals or protocol spec). Reading the technical papers could help a lot.

The library always creates its underlying, "real" socket as a datagram one (check channel.cpp, CChannel::open).

梦纸 2024-11-10 23:27:59

前言:有用的宏

以下是我为自己编写的首选套接字演示文件中的一些有用的宏,这些宏清楚地说明了如何获取 UDPTCP 数据包。

从这些文件中:

  1. socket__geeksforgeeks_udp_server_GS_edit_GREAT.c
  2. socket__geeksforgeeks_udp_client_GS_edit_GREAT.c

...您可以找到这些宏:

// See: https://linux.die.net/man/7/ip
// AF = "Address Family"
// INET = "Internet"
// AF_INET = IPv4 internet protocols
// AF_INET6 = IPv6 internet protocols; see: https://linux.die.net/man/2/socket
// DGRAM = "Datagram" (UDP)
//
// IPv4
#define SOCKET_TYPE_TCP_IPV4              AF_INET, SOCK_STREAM, 0
#define SOCKET_TYPE_UDP_IPV4              AF_INET, SOCK_DGRAM, 0
#define SOCKET_TYPE_RAW_IPV4(protocol)    AF_INET, SOCK_RAW, (protocol)
// IPv6
#define SOCKET_TYPE_TCP_IPV6              AF_INET6, SOCK_STREAM, 0
#define SOCKET_TYPE_UDP_IPV6              AF_INET6, SOCK_DGRAM, 0
#define SOCKET_TYPE_RAW_IPV6(protocol)    AF_INET6, SOCK_RAW, (protocol)

使用示例:

int socket_tcp = socket(SOCKET_TYPE_TCP_IPV4);
int socket_udp = socket(SOCKET_TYPE_UDP_IPV4);
// See also: https://www.binarytides.com/raw-sockets-c-code-linux/
int socket_raw = socket(SOCKET_TYPE_RAW_IPV4(IPPROTO_RAW));

现在回到问题:

什么是SOCK_DGRAMSOCK_STREAM

简要概述

UDP --(是使用的协议)--> AF_INET、SOCK_DGRAMAF_INET6、SOCK_DGRAM
TCP --(是使用的协议)--> AF_INET、SOCK_STREAMAF_INET6、SOCK_STREAM

示例:来自 https://linux.die.net/man/7/ip(或者通过运行 man 7 ip 在终端手册页中显示):

tcp_socket = 套接字(AF_INET, SOCK_STREAM, 0);
udp_socket = 套接字(AF_INET, SOCK_DGRAM, 0);
raw_socket = socket(AF_INET, SOCK_RAW, 协议);

详细摘要

参考 int socket(AddressFamily, Type, Protocol) 套接字创建函数文档 此处此处(也可以通过运行 man 2 socket 查看)。它允许您指定以下 3 个参数:

  1. 地址族
  2. 套接字类型
  3. 协议

然而,对于许多(如果不是大多数)用例来说,这些参数最有用的选项通常是:

  1. 地址族:AF_INET (对于 IPv4 地址)或 AF_INET6 (对于 IPv6 地址)。

  2. 套接字类型:SOCK_DGRAMSOCK_STREAM

  3. 协议:只需使用 0 即可允许其使用默认协议,如上面的文档链接中指定的(已添加强调):

    <块引用>

    协议:指定与套接字一起使用的特定协议。 指定协议参数 0 会导致套接字子例程默认使用所请求的返回套接字类型的典型协议。

  4. SOCK_DGRAM:如果您使用 AF_INET 创建套接字作为

    int s = 套接字(AF_INET, SOCK_DGRAM, 0)
    

    或使用AF_INET6作为

    int s = 套接字(AF_INET6, SOCK_DGRAM, 0)
    

    ...当(AF_INETAF_INET6)地址族和 SOCK_DGRAM< 时,套接字默认使用 UDP 协议/code> 已选择套接字类型。

    1. UNIX 地址族域 (AF_UNIX) 中:通过 AF_UNIX 在同一操作系统上运行的进程之间进行通信时 地址族,这类似于进程间消息队列。
    2. 互联网地址系列域(AF_INETAF_INET6 中:本地进程与运行在其上的进程之间进行通信时远程主机通过AF_INET地址族,这是“在用户数据报协议/互联网协议(UDP/IP)协议上实现的。”

  5. SOCK_STREAM:如果您使用 AF_INET 创建套接字,则为

    int s = 套接字(AF_INET, SOCK_STREAM, 0)
    

    或使用AF_INET6作为

    int s = 套接字(AF_INET6, SOCK_STREAM, 0)
    

    ...当(AF_INETAF_INET6)地址族和 SOCK_STREAM< 时,套接字默认使用 TCP 协议/code> 已选择套接字类型。

    1. UNIX 地址族域 (AF_UNIX) 中:通过 AF_UNIX 在同一操作系统上运行的进程之间进行通信时 Address Family,这种类型的套接字“像管道一样工作”IPC(进程间通信)机制。
    2. 互联网地址系列域(AF_INETAF_INET6 中:本地进程与运行在其上的进程之间进行通信时远程主机通过AF_INET地址族,这是“在传输控制协议/互联网协议(TCP/IP)协议上实现的。”

详细信息

在下面的说明中,无论我(或他们,在引用的部分中)使用 AF_INET(对于 IPv4 地址),请记住您也可以使用 AF_INET6 (对于 IPv6 地址)如果您愿意的话。

在基于套接字的通信中,包括在同一台计算机上的两个正在运行的进程之间或两台单独的计算机之间来回发送 UDP/IP 和 TCP/IP 以太网数据包,您必须指定地址族(这些常量以AF_开头)和套接字类型(这些常量以SOCK_开头)代码>)。

我找到的有关套接字的最佳文档毫无疑问来自 IBM.com,例如:

  1. int socket(AddressFamily, Type, Protocol) function: https://www.ibm.com/docs/en/aix/7.1?topic=s-套接字子例程
  2. 地址族:https:/ /www.ibm.com/docs/en/aix/7.1?topic=domains-address-families 以及此处的
  3. 套接字类型:https://www.ibm.com/docs/en/aix/7.1?topic=protocols-socket-types

了解更多信息在“套接字”上,单击上面的链接之一后,单击左侧导航窗格中的链接。

其他优秀文档也可以在 linux.die.net 上找到,例如 ip(7) 页面位于此处

地址族 (AF_) 域

从上面的“地址族”链接,首先,我们了解各种套接字地址族 (AF) 域,这是理解的先决条件套接字类型。这是该信息(添加了强调,并且我的注释添加在方括号 [] 中):

采用地址族 (AF) 作为参数的套接字子例程可以使用 AF_UNIX (UNIX)AF_INET ( Internet)、AF_NS(Xerox 网络系统)或 AF_NDD(操作系统的网络设备驱动程序)协议。这些地址族是以下通信域的一部分:

UNIX:当指定AF_UNIX地址族时,在同一操作系统上运行的进程之间提供套接字通信。 UNIX 域中的套接字名称是一串 ASCII 字符,其最大长度取决于所使用的机器。

Internet:当指定AF_INET地址族时,在本地进程与远程主机上运行的进程之间提供套接字通信。 Internet 域要求您的系统上安装传输控制协议/Internet 协议 (TCP/IP)。互联网域中的套接字名称是一个互联网地址,由 32 位 IP 地址 [例如:192.168.0.1] 和 16 位端口地址 [0 中的任意数字组成65535这里是常见 TCP 和 UDP 端口号的列表]。

NDD:当指定AF_NDD地址族时,在本地进程和远程主机上运行的进程之间提供套接字通信。 NDD 域使应用程序能够直接在物理网络之上运行。这与 Internet 域形成鲜明对比,在 Internet 域中,应用程序在 TCP用户数据报协议 (UDP) 等传输协议之上运行。 NDD 域中的套接字名称由操作系统 NDD 名称和协议相关的第二部分组成。

通信域[例如:AF_UNIXAF_INET]由可加载的域数据结构描述。域内的通信协议[例如:SOCK_DGRAM (UDP) 或 SOCK_STREAM (TCP)] 由系统内定义的结构来描述对于配置的每个协议实现。当请求创建套接字时,系统使用通信域的名称线性搜索已配置域的列表。如果找到该域,则将查询该域支持的协议表,以获取适合正在创建的套接字类型或特定协议请求的协议。 (原始域可能存在通配符条目。)如果多个协议条目满足请求,则选择第一个。

套接字类型 (SOCK_)

从上面的“套接字类型”链接,我们了解了各种“底层通信协议”(强调号已添加,我的注释添加在方括号中 [ ]):

套接字根据通信属性进行分类。进程通常在相同类型的套接字之间进行通信。但是,如果底层通信协议支持通信,则不同类型的套接字可以通信。

每个套接字都有一个关联的类型,它描述使用该套接字进行通信的语义。 套接字类型决定套接字通信属性,例如可靠性、排序和防止消息重复。基本的套接字类型集在 sys/socket.h 文件中定义:

/*标准套接字类型*/
#define SOCK_STREAM 1 /*虚拟电路*/
#define SOCK_DGRAM 2 /*数据报*/
#define SOCK_RAW 3 /*原始套接字*/
#define SOCK_RDM 4 /*可靠传递消息*/
#define SOCK_CONN_DGRAM 5 /*连接数据报*/

可以定义其他套接字类型。

操作系统支持以下基本套接字集:

<小时>

SOCK_DGRAM:提供数据报,它们是固定最大长度的无连接消息。这种类型的套接字一般用于短消息,例如名称服务器或时间服务器,因为无法保证消息传递的顺序和可靠性。

UNIX 域 [AF_UNIX] 中,SOCK_DGRAM 套接字类型类似于消息队列。在Internet 域 [AF_INET] 中,SOCK_DGRAM 套接字类型是在用户数据报协议/Internet 协议(UDP/IP) 协议上实现的。

数据报套接字支持双向数据流,这种数据流不是顺序的、可靠的或不重复的。在数据报套接字上接收消息的进程可能会发现消息重复或顺序与发送顺序不同。然而,数据中的记录边界被保留。数据报套接字密切模拟了许多当代分组交换网络中的设施。

SOCK_STREAM:提供有序的、双向的字节流以及流数据的传输机制。这种套接字类型以可靠的方式按顺序传输数据,并具有带外功能。

UNIX 域 [AF_UNIX] 中,SOCK_STREAM 套接字类型像管道一样工作。在Internet 域 [AF_INET] 中,SOCK_STREAM 套接字类型是在传输控制协议/Internet 协议(TCP/IP) 协议上实现的。

流套接字提供双向、可靠、有序且不重复的数据流,没有记录边界。除了数据流的双向性之外,一对连接的流套接字提供了与管道几乎相同的接口。

SOCK_RAW:提供对内部网络协议和接口的访问。这种类型的套接字仅适用于具有 root 用户权限的用户,或具有 CAP_NUMA_ATTACH 功能的非 root 用户。 (对于非 root 原始套接字访问,chuser 命令分配 CAP_NUMA_ATTACH 功能以及 CAP_PROPAGATE 有关详细信息,请参阅 chuser 命令。)

原始套接字允许应用程序直接访问较低级别的通信协议。原始套接字适用于想要利用某些无法通过普通接口直接访问的协议功能的高级用户,或者想要在现有低级协议之上构建新协议的高级用户。

原始套接字通常是面向数据报的,尽管它们的确切特征取决于协议提供的接口。

SOCK_SEQPACKET:提供有序、可靠且不重复的信息流。

SOCK_CONN_DGRAM:提供面向连接的数据报服务。这种类型的套接字支持双向数据流,数据是有序的、不重复的,但不可靠。由于这是面向连接的服务,因此必须在数据传输之前连接套接字。目前,只有网络设备驱动程序(NDD)域中的异步传输模式(ATM)协议支持该套接字类型。

它们如何工作?

SOCK_DGRAMSOCK_RAW 套接字类型允许应用程序将数据报发送到 发送 子例程。应用程序可以使用 recv 通过套接字接收数据报 子例程。当使用 SOCK_RAW 套接字类型与低级协议或硬件接口进行通信时,Protocol 参数非常重要。应用程序必须指定进行通信的地址族。

这是使用 SOCK_STREAM(TCP 协议)套接字类型进行通信所需的函数调用的一般序列:

SOCK_STREAM 套接字类型是全双工字节流。必须先连接流套接字,然后才能在其上发送或接收任何数据。当使用流套接字进行数据传输时,应用程序需要执行以下序列:

  1. 使用 connect子例程。
  2. 使用阅读write 子例程或 < a href="https://www.ibm.com/docs/en/ssw_aix_71/communicationtechref/send.html" rel="noreferrer">发送recv 用于传输数据的子例程。
  3. 使用关闭完成会话的子例程。

应用程序可以使用sendrecv子例程来管理带外数据。

使用 SOCK_STREAM 时可能返回或在 errno 变量中设置的错误:

SOCK_STREAM 通信协议旨在防止数据丢失或重复。如果对端协议有缓冲空间的一段数据无法在合理的时间内成功传输,则连接断开。发生这种情况时,socket 子例程会指示一个错误并返回-1 的值和 errno 全局变量设置为 ETIMEDOUT。如果进程发送中断的流,则会引发 SIGPIPE 信号。无法处理该信号的进程终止。当带外数据到达套接字时,SIGURG 信号将发送到进程组。

与套接字关联的进程组可以通过 SIOCGPGRPSIOCSPGRP ioctl 操作读取或设置。要接收任何数据的信号,请同时使用 SIOCSPGRPFIOASYNC ioctl 操作。这些操作在 sys/ioctl.h 文件中定义。

这大约涵盖了它。我希望在 eRCaGuy_hello_world 存储库中编写一些基本演示 c 目录 很快。

主要参考:

  1. [我的答案] 在manpages中unix命令名称后显示的括号中的数字是多少?
  2. **************************** * https://linux.die.net/man/7/ip
  3. https://linux.die.net/man/2/socket
  4. https://linux.die.net/man/7/tcp
  5. https://linux.die.net/man/7/udp
  6. int socket(adversefamily,type,stroment)函数: https://www.ibm.com/ docs/en/aix/7.1?主题= s-socket-subroutine
  7. 地址自己: https://www.ibm.com/docs/en/aix/7.1?topic = domains-address-families sere
  8. 插座类型: https://www.ibm.com/docs/docs/docs/en/aix/aix/aix/aix/7.1?topic = protocols-socket-types

相关:

  1. 什么是sock_dgramsock_stream
  2. 什么时候ipproto_udp必需?
  3. stackoverflow.com/q/5385312/4561887“> ipproto_ip vs ipproto_tcp/ipproto_udp

Preface: useful macros

Here are some useful macros from my go-to socket demo files I wrote for myself, which make it clear how to get UDP vs TCP packets.

From these files:

  1. socket__geeksforgeeks_udp_server_GS_edit_GREAT.c
  2. socket__geeksforgeeks_udp_client_GS_edit_GREAT.c

...you can find these macros:

// See: https://linux.die.net/man/7/ip
// AF = "Address Family"
// INET = "Internet"
// AF_INET = IPv4 internet protocols
// AF_INET6 = IPv6 internet protocols; see: https://linux.die.net/man/2/socket
// DGRAM = "Datagram" (UDP)
//
// IPv4
#define SOCKET_TYPE_TCP_IPV4              AF_INET, SOCK_STREAM, 0
#define SOCKET_TYPE_UDP_IPV4              AF_INET, SOCK_DGRAM, 0
#define SOCKET_TYPE_RAW_IPV4(protocol)    AF_INET, SOCK_RAW, (protocol)
// IPv6
#define SOCKET_TYPE_TCP_IPV6              AF_INET6, SOCK_STREAM, 0
#define SOCKET_TYPE_UDP_IPV6              AF_INET6, SOCK_DGRAM, 0
#define SOCKET_TYPE_RAW_IPV6(protocol)    AF_INET6, SOCK_RAW, (protocol)

Usage examples:

int socket_tcp = socket(SOCKET_TYPE_TCP_IPV4);
int socket_udp = socket(SOCKET_TYPE_UDP_IPV4);
// See also: https://www.binarytides.com/raw-sockets-c-code-linux/
int socket_raw = socket(SOCKET_TYPE_RAW_IPV4(IPPROTO_RAW));

Now back to the question:

What is SOCK_DGRAM and SOCK_STREAM?

Brief Summary

UDP --(is the protocol utilized by)--> AF_INET, SOCK_DGRAM or AF_INET6, SOCK_DGRAM
TCP --(is the protocol utilized by)--> AF_INET, SOCK_STREAM or AF_INET6, SOCK_STREAM

Examples: from https://linux.die.net/man/7/ip (or as shown in your terminal man pages by running man 7 ip):

tcp_socket = socket(AF_INET, SOCK_STREAM, 0);
udp_socket = socket(AF_INET, SOCK_DGRAM, 0);
raw_socket = socket(AF_INET, SOCK_RAW, protocol);

Long Summary

Reference the int socket(AddressFamily, Type, Protocol) socket creation function documentation here and here (can also be viewed by running man 2 socket). It allows you to specify these 3 parameters:

  1. Address Family
  2. Socket Type
  3. Protocol

For many if not most use-cases, however, the most-useful options for these parameters are frequently:

  1. Address Family: AF_INET (for IPv4 addresses) or AF_INET6 (for IPv6 addresses).

  2. Socket Type: SOCK_DGRAM or SOCK_STREAM.

  3. Protocol: just use 0 to allow it to use default protocols, as specified from the documentation link above (emphasis added):

    Protocol: Specifies a particular protocol to be used with the socket. Specifying the Protocol parameter of 0 causes the socket subroutine to default to the typical protocol for the requested type of returned socket.

  4. SOCK_DGRAM: if you create your socket with AF_INET as

    int s = socket(AF_INET, SOCK_DGRAM, 0)
    

    or with AF_INET6 as

    int s = socket(AF_INET6, SOCK_DGRAM, 0)
    

    ...the socket utilizes the UDP protocol by default when the (AF_INET or AF_INET6) address family and SOCK_DGRAM Socket Types are selected.

    1. In the UNIX Address Family domain (AF_UNIX): when communicating between processes running on the same operating system via the AF_UNIX Address Family, this is similar to an inter-process message queue.
    2. In the Internet Address Family domain (AF_INET and AF_INET6): when communicating between a local process and a process running on a remote host via the AF_INET Address Family, this is "implemented on the User Datagram Protocol/Internet Protocol (UDP/IP) protocol."
  5. SOCK_STREAM: if you create your socket with AF_INET as

    int s = socket(AF_INET, SOCK_STREAM, 0)
    

    or with AF_INET6 as

    int s = socket(AF_INET6, SOCK_STREAM, 0)
    

    ...the socket utilizes the TCP protocol by default when the (AF_INET or AF_INET6) address family and SOCK_STREAM Socket Types are selected.

    1. In the UNIX Address Family domain (AF_UNIX): when communicating between processes running on the same operating system via the AF_UNIX Address Family, this type of socket "works like a pipe" IPC (Inter-process Communication) mechanism.
    2. In the Internet Address Family domain (AF_INET and AF_INET6): when communicating between a local process and a process running on a remote host via the AF_INET Address Family, this is "implemented on the Transmission Control Protocol/Internet Protocol (TCP/IP) protocol."

Details

In the explanation below, wherever I (or they, in the quoted sections) use AF_INET (for IPv4 addresses), keep in mind you can also use AF_INET6 (for IPv6 addresses) if you like.

In socket-based communication, including for sending both UDP/IP and TCP/IP Ethernet data packets back and forth between two running processes on the same computer, or between two separate computers, you must specify both the Address Family (these constants begin with AF_) and Socket Type (these constans begin with SOCK_).

The best documentation I have found on sockets, hands-down, is from IBM.com, such as here:

  1. int socket(AddressFamily, Type, Protocol) function: https://www.ibm.com/docs/en/aix/7.1?topic=s-socket-subroutine
  2. Address Families: https://www.ibm.com/docs/en/aix/7.1?topic=domains-address-families and here
  3. Socket Types: https://www.ibm.com/docs/en/aix/7.1?topic=protocols-socket-types

For additional information on "Sockets", click the links in the left-hand navigation pane after clicking one of the links above.

Other excellent documentation can also be found on linux.die.net, such as the ip(7) page here.

Address Family (AF_) Domains

From the "Address Families" link above, first, we learn about the various socket Address Families (AF) domains, which are a prerequisite to understanding the socket types. Here is that information (emphasis added, and my notes added in square brackets []):

A socket subroutine that takes an address family (AF) as a parameter can use AF_UNIX (UNIX), AF_INET (Internet), AF_NS (Xerox Network Systems), or AF_NDD (Network Device Drivers of the operating sytem) protocol. These address families are part of the following communication domains:

UNIX: Provides socket communication between processes running on the same operating system when an address family of AF_UNIX is specified. A socket name in the UNIX domain is a string of ASCII characters whose maximum length depends on the machine in use.

Internet: Provides socket communication between a local process and a process running on a remote host when an address family of AF_INET is specified. The Internet domain requires that Transmission Control Protocol/Internet Protocol (TCP/IP) be installed on your system. A socket name in the Internet domain is an Internet address, made up of a 32-bit IP address [ex: 192.168.0.1] and a 16-bit port address [any number from 0 to 65535; here is a list of common TCP and UDP port numbers].

NDD: Provides socket communication between a local process and a process running on a remote host when an address family of AF_NDD is specified. The NDD domain enables applications to run directly on top of physical networks. This is in contrast to the Internet domain, in which applications run on top of transport protocols such as TCP, or User Datagram Protocol (UDP). A socket name in the NDD domain consists of operating system NDD name and a second part that is protocol dependent.

Communication domains [ex: AF_UNIX or AF_INET] are described by a domain data structure that is loadable. Communication protocols [ex: SOCK_DGRAM (UDP) or SOCK_STREAM (TCP)] within a domain are described by a structure that is defined within the system for each protocol implementation configured. When a request is made to create a socket, the system uses the name of the communication domain to search linearly the list of configured domains. If the domain is found, the domain's table of supported protocols is consulted for a protocol appropriate for the type of socket being created or for a specific protocol request. (A wildcard entry may exist for a raw domain.) Should multiple protocol entries satisfy the request, the first is selected.

Socket Types (SOCK_)

From the "Socket Types" link above, we learn about the various "underlying communication protocols" (emphasis added, and my notes added in square brackets []):

Sockets are classified according to communication properties. Processes usually communicate between sockets of the same type. However, if the underlying communication protocols support the communication, sockets of different types can communicate.

Each socket has an associated type, which describes the semantics of communications using that socket. The socket type determines the socket communication properties such as reliability, ordering, and prevention of duplication of messages. The basic set of socket types is defined in the sys/socket.h file:

/*Standard socket types */
#define  SOCK_STREAM             1 /*virtual circuit*/
#define  SOCK_DGRAM              2 /*datagram*/
#define  SOCK_RAW                3 /*raw socket*/
#define  SOCK_RDM                4 /*reliably-delivered message*/
#define  SOCK_CONN_DGRAM         5 /*connection datagram*/

Other socket types can be defined.

The operating system supports the following basic set of sockets:


SOCK_DGRAM: Provides datagrams, which are connectionless messages of a fixed maximum length. This type of socket is generally used for short messages, such as a name server or time server, because the order and reliability of message delivery is not guaranteed.

In the UNIX domain [AF_UNIX], the SOCK_DGRAM socket type is similar to a message queue. In the Internet domain [AF_INET], the SOCK_DGRAM socket type is implemented on the User Datagram Protocol/Internet Protocol (UDP/IP) protocol.

A datagram socket supports the bidirectional flow of data, which is not sequenced, reliable, or unduplicated. A process receiving messages on a datagram socket may find messages duplicated or in an order different than the order sent. Record boundaries in data, however, are preserved. Datagram sockets closely model the facilities found in many contemporary packet-switched networks.

SOCK_STREAM: Provides sequenced, two-way byte streams with a transmission mechanism for stream data. This socket type transmits data on a reliable basis, in order, and with out-of-band capabilities.

In the UNIX domain [AF_UNIX], the SOCK_STREAM socket type works like a pipe. In the Internet domain [AF_INET], the SOCK_STREAM socket type is implemented on the Transmission Control Protocol/Internet Protocol (TCP/IP) protocol.

A stream socket provides for the bidirectional, reliable, sequenced, and unduplicated flow of data without record boundaries. Aside from the bidirectionality of data flow, a pair of connected stream sockets provides an interface nearly identical to pipes.

SOCK_RAW: Provides access to internal network protocols and interfaces. This type of socket is available only to users with root-user authority, or to non-root users who have the CAP_NUMA_ATTACH capability. (For non-root raw socket access, the chuser command assigns the CAP_NUMA_ATTACH capability, along with CAP_PROPAGATE. For further information, refer to the chuser command.)

Raw sockets allow an application to have direct access to lower-level communication protocols. Raw sockets are intended for advanced users who want to take advantage of some protocol feature that is not directly accessible through a normal interface, or who want to build new protocols on top of existing low-level protocols.

Raw sockets are normally datagram-oriented, though their exact characteristics are dependent on the interface provided by the protocol.

SOCK_SEQPACKET: Provides sequenced, reliable, and unduplicated flow of information.

SOCK_CONN_DGRAM: Provides connection-oriented datagram service. This type of socket supports the bidirectional flow of data, which is sequenced and unduplicated, but is not reliable. Because this is a connection-oriented service, the socket must be connected prior to data transfer. Currently, only the Asynchronous Transfer Mode (ATM) protocol in the Network Device Driver (NDD) domain supports this socket type.

How do they work?

The SOCK_DGRAM and SOCK_RAW socket types allow an application program to send datagrams to correspondents named in send subroutines. Application programs can receive datagrams through sockets using the recv subroutines. The Protocol parameter is important when using the SOCK_RAW socket type to communicate with low-level protocols or hardware interfaces. The application program must specify the address family in which the communication takes place.

This is the general sequence of function calls required to communicate using SOCK_STREAM (TCP protocol) socket types:

The SOCK_STREAM socket types are full-duplex byte streams. A stream socket must be connected before any data can be sent or received on it. When using a stream socket for data transfer, an application program needs to perform the following sequence:

  1. Create a connection to another socket with the connect subroutine.
  2. Use the read and write subroutines or the send and recv subroutines to transfer data.
  3. Use the close subroutine to finish the session.

An application program can use the send and recv subroutines to manage out-of-band data.

Possible errors returned or set in the errno variable when using SOCK_STREAM:

SOCK_STREAM communication protocols are designed to prevent the loss or duplication of data. If a piece of data for which the peer protocol has buffer space cannot be successfully transmitted within a reasonable period of time, the connection is broken. When this occurs, the socket subroutine indicates an error with a return value of -1 and the errno global variable is set to ETIMEDOUT. If a process sends on a broken stream, a SIGPIPE signal is raised. Processes that cannot handle the signal terminate. When out-of-band data arrives on a socket, a SIGURG signal is sent to the process group.

The process group associated with a socket can be read or set by either the SIOCGPGRP or SIOCSPGRP ioctl operation. To receive a signal on any data, use both the SIOCSPGRP and FIOASYNC ioctl operations. These operations are defined in the sys/ioctl.h file.

That about covers it. I hope to write some basic demos in my eRCaGuy_hello_world repo in the c dir soon.

Main References:

  1. [my answer] What does the number in parentheses shown after Unix command names in manpages mean?
  2. *****https://linux.die.net/man/7/ip
  3. https://linux.die.net/man/2/socket
  4. https://linux.die.net/man/7/tcp
  5. https://linux.die.net/man/7/udp
  6. int socket(AddressFamily, Type, Protocol) function: https://www.ibm.com/docs/en/aix/7.1?topic=s-socket-subroutine
  7. Address Families: https://www.ibm.com/docs/en/aix/7.1?topic=domains-address-families and here
  8. Socket Types: https://www.ibm.com/docs/en/aix/7.1?topic=protocols-socket-types

Related:

  1. What is SOCK_DGRAM and SOCK_STREAM?
  2. when is IPPROTO_UDP required?
  3. IPPROTO_IP vs IPPROTO_TCP/IPPROTO_UDP
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文