什么是SOCK_DGRAM和SOCK_STREAM?
我刚刚遇到一个奇怪的事情,我看到应用程序默认情况下使用 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
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 usesSOCK_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.
Berkley Sockets API 背后的想法之一是它可以使用不同的协议家庭 - 不仅仅是互联网协议(IP)。相反,您拥有一个可以处理各种“地址族”的 API,例如:
AF_INET
AF_IPX< /code>
AF_APPLETALK
AF_NETBIOS
AF_INET6
AF_IRDA
AF_BTH
每个协议系列通常对于如何在套接字上处理数据有一些相似的概念:
SOCK_STREAM
(IP 人员称之为 TCP)SOCK_DGRAM
(IP 人员将其称为 UDP)不同的地址族对这些基本概念有不同的术语:
要点是:
类似地,如果我正在创建一个套接字红外线(IrDA,
AF_IRDA
):所以你说:
套接字会为我解决这个问题。
Bonus
最初只有两个协议选项:
SOCK_DGRAM
)SOCK_STREAM
)后来有其他协议选择添加了:
SOCK_RDM
- “可靠数据报多播” - 已过时;请勿在新程序中使用)SOCK_SEQPACKET
)不保证任何给定的地址系列都支持此类协议选择;但有些人这样做。
Bonus Bonus Chatter
希望您现在明白为什么在调用中传递
IPPROTO_TCP
协议来创建套接字是多余的:您已经说过您想要一个
SOCK_STREAM
。您不需要在其之上强制使用TCP
。同样,调用: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.:
AF_INET
AF_IPX
AF_APPLETALK
AF_NETBIOS
AF_INET6
AF_IRDA
AF_BTH
Each protocol family generally has a few similar concepts of how data will be handled on a socket:
SOCK_STREAM
(what an IP person would call TCP)SOCK_DGRAM
(what an IP person would call UDP)Different address families have different terms for these basic concepts:
The point is:
Similarly, if i were creating a socket over Infrared (IrDA,
AF_IRDA
):So you say:
And Sockets will figure it out for me.
Bonus
Originally there was only the two protocol options:
SOCK_DGRAM
)SOCK_STREAM
)Later other protocol choices were added:
SOCK_RDM
- "Reliable Datagram Multicast" - obsolete; do not use in new programs)SOCK_SEQPACKET
)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:You already said you wanted a
SOCK_STREAM
. You don't need to forceTCP
on top of it. In the same way it's redundant to call: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.
更新:我的回答似乎不再相关,但最初的问题提到了 UDT,它是构建在 UDP 之上的面向连接的协议。更多信息请参见:http://en.wikipedia.org/wiki/UDP-based_Data_Transfer_Protocol
UDT 似乎提供了模仿经典 BSD 套接字 API 的 API,因此它可以用作面向流和数据报的应用程序的直接替代品。检查例如
sendmsg
和recvmsg
- 如果在使用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
andrecvmsg
- both throw an exception if used on a socket created withSOCK_STREAM
, and all the stream oriented APIs throw an exception for socket created withSOCK_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
).前言:有用的宏
以下是我为自己编写的首选套接字演示文件中的一些有用的宏,这些宏清楚地说明了如何获取 UDP 与 TCP 数据包。
从这些文件中:
...您可以找到这些宏:
使用示例:
现在回到问题:
简要概述
UDP --(是使用的协议)-->
AF_INET、SOCK_DGRAM
或AF_INET6、SOCK_DGRAM
TCP --(是使用的协议)-->
AF_INET、SOCK_STREAM
或AF_INET6、SOCK_STREAM
示例:来自 https://linux.die.net/man/7/ip(或者通过运行
man 7 ip
在终端手册页中显示):详细摘要
参考
int socket(AddressFamily, Type, Protocol)
套接字创建函数文档 此处 和 此处(也可以通过运行man 2 socket
查看)。它允许您指定以下 3 个参数:然而,对于许多(如果不是大多数)用例来说,这些参数最有用的选项通常是:
地址族:
AF_INET
(对于 IPv4 地址)或AF_INET6
(对于 IPv6 地址)。套接字类型:
SOCK_DGRAM
或SOCK_STREAM
。协议:只需使用
0
即可允许其使用默认协议,如上面的文档链接中指定的(已添加强调):<块引用>
协议:指定与套接字一起使用的特定协议。 指定协议参数
0
会导致套接字子例程默认使用所请求的返回套接字类型的典型协议。SOCK_DGRAM
:如果您使用
AF_INET
创建套接字作为或使用
AF_INET6
作为...当(
AF_INET
或AF_INET6
)地址族和SOCK_DGRAM< 时,套接字默认使用 UDP 协议/code> 已选择套接字类型。
AF_UNIX
) 中:通过AF_UNIX 在同一操作系统上运行的进程之间进行通信时
地址族,这类似于进程间消息队列。AF_INET
和AF_INET6
) 中:本地进程与运行在其上的进程之间进行通信时远程主机通过AF_INET
地址族,这是“在用户数据报协议/互联网协议(UDP/IP)协议上实现的。”SOCK_STREAM
:如果您使用AF_INET
创建套接字,则为或使用
AF_INET6
作为...当(
AF_INET
或AF_INET6
)地址族和SOCK_STREAM< 时,套接字默认使用 TCP 协议/code> 已选择套接字类型。
AF_UNIX
) 中:通过AF_UNIX 在同一操作系统上运行的进程之间进行通信时
Address Family,这种类型的套接字“像管道一样工作”IPC(进程间通信)机制。AF_INET
和AF_INET6
) 中:本地进程与运行在其上的进程之间进行通信时远程主机通过AF_INET
地址族,这是“在传输控制协议/互联网协议(TCP/IP)协议上实现的。”详细信息
在下面的说明中,无论我(或他们,在引用的部分中)使用
AF_INET
(对于 IPv4 地址),请记住您也可以使用AF_INET6
(对于 IPv6 地址)如果您愿意的话。在基于套接字的通信中,包括在同一台计算机上的两个正在运行的进程之间或两台单独的计算机之间来回发送 UDP/IP 和 TCP/IP 以太网数据包,您必须指定地址族(这些常量以
AF_
开头)和套接字类型(这些常量以SOCK_
开头)代码>)。我找到的有关套接字的最佳文档毫无疑问来自 IBM.com,例如:
int socket(AddressFamily, Type, Protocol)
function: https://www.ibm.com/docs/en/aix/7.1?topic=s-套接字子例程了解更多信息在“套接字”上,单击上面的链接之一后,单击左侧导航窗格中的链接。
其他优秀文档也可以在 linux.die.net 上找到,例如
ip(7)
页面位于此处。地址族 (
AF_
) 域从上面的“地址族”链接,首先,我们了解各种套接字地址族 (AF) 域,这是理解的先决条件套接字类型。这是该信息(添加了强调,并且我的注释添加在方括号 [] 中):
套接字类型 (
SOCK_
)从上面的“套接字类型”链接,我们了解了各种“底层通信协议”(强调号已添加,我的注释添加在方括号中 [ ]):
它们如何工作?
这是使用
SOCK_STREAM
(TCP 协议)套接字类型进行通信所需的函数调用的一般序列:使用
SOCK_STREAM
时可能返回或在errno
变量中设置的错误:这大约涵盖了它。我希望在 eRCaGuy_hello_world 存储库中编写一些基本演示
c
目录 很快。主要参考:
int socket(adversefamily,type,stroment)函数: https://www.ibm.com/ docs/en/aix/7.1?主题= s-socket-subroutine
相关:
sock_dgram
和sock_stream
?ipproto_udp
必需?ipproto_ip
vsipproto_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:
...you can find these macros:
Usage examples:
Now back to the question:
Brief Summary
UDP --(is the protocol utilized by)-->
AF_INET, SOCK_DGRAM
orAF_INET6, SOCK_DGRAM
TCP --(is the protocol utilized by)-->
AF_INET, SOCK_STREAM
orAF_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
):Long Summary
Reference the
int socket(AddressFamily, Type, Protocol)
socket creation function documentation here and here (can also be viewed by runningman 2 socket
). It allows you to specify these 3 parameters:For many if not most use-cases, however, the most-useful options for these parameters are frequently:
Address Family:
AF_INET
(for IPv4 addresses) orAF_INET6
(for IPv6 addresses).Socket Type:
SOCK_DGRAM
orSOCK_STREAM
.Protocol: just use
0
to allow it to use default protocols, as specified from the documentation link above (emphasis added):SOCK_DGRAM
: if you create your socket withAF_INET
asor with
AF_INET6
as...the socket utilizes the UDP protocol by default when the (
AF_INET
orAF_INET6
) address family andSOCK_DGRAM
Socket Types are selected.AF_UNIX
): when communicating between processes running on the same operating system via theAF_UNIX
Address Family, this is similar to an inter-process message queue.AF_INET
andAF_INET6
): when communicating between a local process and a process running on a remote host via theAF_INET
Address Family, this is "implemented on the User Datagram Protocol/Internet Protocol (UDP/IP) protocol."SOCK_STREAM
: if you create your socket withAF_INET
asor with
AF_INET6
as...the socket utilizes the TCP protocol by default when the (
AF_INET
orAF_INET6
) address family andSOCK_STREAM
Socket Types are selected.AF_UNIX
): when communicating between processes running on the same operating system via theAF_UNIX
Address Family, this type of socket "works like a pipe" IPC (Inter-process Communication) mechanism.AF_INET
andAF_INET6
): when communicating between a local process and a process running on a remote host via theAF_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 useAF_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 withSOCK_
).The best documentation I have found on sockets, hands-down, is from IBM.com, such as here:
int socket(AddressFamily, Type, Protocol)
function: https://www.ibm.com/docs/en/aix/7.1?topic=s-socket-subroutineFor 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_
) DomainsFrom 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 []):
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 []):
How do they work?
This is the general sequence of function calls required to communicate using
SOCK_STREAM
(TCP protocol) socket types:Possible errors returned or set in the
errno
variable when usingSOCK_STREAM
:That about covers it. I hope to write some basic demos in my eRCaGuy_hello_world repo in the
c
dir soon.Main References:
int socket(AddressFamily, Type, Protocol)
function: https://www.ibm.com/docs/en/aix/7.1?topic=s-socket-subroutineRelated:
SOCK_DGRAM
andSOCK_STREAM
?IPPROTO_UDP
required?IPPROTO_IP
vsIPPROTO_TCP
/IPPROTO_UDP