这是我所在组织的一位软件工程师提出的问题。我感兴趣的是最广义的定义。


当前回答

总结

TCP套接字是在特定TCP连接或监听状态的上下文中由IP地址和端口定义的端点实例。

端口是定义服务端点的虚拟化标识符(与服务实例端点又名会话标识符不同)。

TCP套接字不是一个连接,而是一个特定连接的端点。

可以存在到服务端点的并发连接,因为连接由其本地和远程端点标识,从而允许将流量路由到特定的服务实例。

对于给定的地址/端口组合,只能有一个侦听器套接字。

博览会

这是一个有趣的问题,它迫使我重新审视一些我自以为已经完全了解的东西。你可能会认为“插座”这样的名字是不言自明的:选择它显然是为了唤起你插入网线的端点的形象,有很强的功能相似之处。然而,在网络用语中,“套接字”这个词承载了如此多的负担,以至于有必要仔细地重新检查。

在最广泛的意义上,端口是一个入口或出口点。虽然不在网络环境中使用,但法语单词porte的字面意思是门或网关,进一步强调了端口是运输端点的事实,无论您运送数据还是大型钢铁集装箱。

为了本讨论的目的,我将只考虑TCP-IP网络的上下文。OSI模型非常好,但从未完全实现,更不用说在高流量、高压力条件下广泛部署。

IP地址和端口的组合严格地称为端点,有时称为套接字。这种用法起源于RFC793,即最初的TCP规范。

TCP连接由两个端点定义,也就是套接字。

端点(套接字)由网络地址和端口标识符的组合定义。请注意,address/port并不能完全标识一个套接字(稍后会详细介绍)。

端口的目的是区分给定网络地址上的多个端点。您可以说端口是一个虚拟端点。这种虚拟化使单个网络接口上的多个并发连接成为可能。

它是套接字对(4元组) 包括客户端IP地址, 客户端端口号,服务器IP地址, 和服务器端口号)指定 这两个端点唯一 对象中的每个TCP连接 互联网。(TCP-IP插图卷1,W. Richard Stevens)

在大多数c派生语言中,TCP连接是使用Socket类实例上的方法建立和操作的。虽然在更高的抽象级别上操作是常见的,通常是NetworkStream类的实例,但这通常会公开对套接字对象的引用。对于编码器来说,这个套接字对象似乎表示连接,因为连接是使用套接字对象的方法创建和操作的。

在c#中,要建立一个TCP连接(到一个现有的侦听器),首先要创建一个TcpClient。如果您没有指定TcpClient构造函数的端点,它将使用默认值—以某种方式定义本地端点。然后调用Connect 方法。此方法需要描述另一个端点的参数。

所有这些都有点令人困惑,并导致您相信套接字是一个连接,这是胡说八道。在理查德·多尔曼提出这个问题之前,我一直在这个误解中苦苦挣扎。

在进行了大量阅读和思考之后,我现在确信,使用带有两个参数LocalEndpoint和RemoteEndpoint的构造函数的类TcpConnection会更有意义。当本地端点的默认值是可接受的时,您可能会支持单个参数RemoteEndpoint。这在多址计算机上是不明确的,但是可以使用路由表通过选择到远程端点的最短路由的接口来解决这种不明确。

在其他方面,透明度也将得到提高。套接字不能通过IP地址和端口的组合来识别:

[...]TCP demultiplexes incoming segments using all four values that comprise the local and foreign addresses: destination IP address, destination port number, source IP address, and source port number. TCP cannot determine which process gets an incoming segment by looking at the destination port only. Also, the only one of the [various] endpoints at [a given port number] that will receive incoming connection requests is the one in the listen state. (p255, TCP-IP Illustrated Volume 1, W. Richard Stevens)

正如您所看到的,网络服务有许多具有相同地址/端口的套接字,但在特定地址/端口组合上只有一个侦听器套接字,这不仅是可能的,而且很有可能。典型的库实现提供了一个套接字类,该类的实例用于创建和管理连接。这是非常不幸的,因为它引起了混乱,并导致了两个概念的广泛合并。

Hagrawal不相信我(见评论),所以这里有一个真实的例子。我把一个浏览器连接到http://dilbert.com,然后运行netstat -an -p tcp。输出的最后六行包含两个示例,说明地址和端口不足以唯一地标识一个套接字。在192.168.1.3(我的工作站)和54.252.94.236:80(远程HTTP服务器)之间有两个不同的连接。

  TCP    192.168.1.3:63240      54.252.94.236:80       SYN_SENT
  TCP    192.168.1.3:63241      54.252.94.236:80       SYN_SENT
  TCP    192.168.1.3:63242      207.38.110.62:80       SYN_SENT
  TCP    192.168.1.3:63243      207.38.110.62:80       SYN_SENT
  TCP    192.168.1.3:64161      65.54.225.168:443      ESTABLISHED

由于套接字是连接的端点,因此有两个套接字的地址/端口组合为207.38.110.62:80,另外两个套接字的地址/端口组合为54.252.94.236:80。

我认为哈格拉瓦尔的误解源于我对“认同”一词的谨慎使用。我的意思是“完全的,明确的,唯一的识别”。在上面的示例中,有两个端点的地址/端口组合为54.252.94.236:80。如果你只有地址和端口,你没有足够的信息来区分这些套接字。这些信息不足以识别套接字。

齿顶高

RFC793第2.7节第2段说

连接完全由两端的一对套接字指定。一个 本地套接字可能参与到不同外部的多个连接 套接字。

从编程的角度来看,socket的这个定义没有帮助,因为它与socket对象不同,后者是特定连接的端点。对于程序员(这个问题的大多数读者都是程序员)来说,这是一个至关重要的功能差异。

@plugwash提出了一个显著的观察。

最根本的问题是TCP RFC对socket的定义与所有主流操作系统和库所使用的socket的定义相冲突。

根据定义,RFC是正确的。当一个标准库误用术语时,它不会取代RFC。相反,它给该库的用户带来了一种责任负担,即理解两种解释,并小心用词和上下文。如果RFC不一致,则最新的和最直接适用的RFC优先。

参考文献

TCP-IP图解卷1协议,W. Richard Stevens, 1994 Addison Wesley RFC793,信息科学研究所,南加州大学DARPA RFC147,插座的定义,Joel M. Winett,林肯实验室

其他回答

一个连接套接字(fd)用于本地地址+本地端口+对端地址+对端端口。通过套接字抽象处理recv/发送数据。 一个监听套接字(fd)用于本地地址+本地监听端口。进程可以通过套接字接受新的连接。

A socket is a communication endpoint. A socket is not directly related to the TCP/IP protocol family, it can be used with any protocol your system supports. The C socket API expects you to first get a blank socket object from the system that you can then either bind to a local socket address (to directly retrieve incoming traffic for connection-less protocols or to accept incoming connection requests for connection-oriented protocols) or that you can connect to a remote socket address (for either kind of protocol). You can even do both if you want to control both, the local socket address a socket is bound to and the remote socket address a socket is connected to. For connection-less protocols connecting a socket is even optional but if you don't do that, you'll have to also pass the destination address with every packet you want to send over the socket as how else would the socket know where to send this data to? Advantage is that you can use a single socket to send packets to different socket addresses. Once you have your socket configured and maybe even connected, consider it to be a bi-directional communication pipe. You can use it to pass data to some destination and some destination can use it to pass data back to you. What you write to a socket is send out and what has been received is available for reading.

Ports on the other hand are something that only certain protocols of the TCP/IP protocol stack have. TCP and UDP packets have ports. A port is just a simple number. The combination of source port and destination port identify a communication channel between two hosts. E.g. you may have a server that shall be both, a simple HTTP server and a simple FTP server. If now a packet arrives for the address of that server, how would it know if that is a packet for the HTTP or the FTP server? Well, it will know so as the HTTP server will run on port 80 and the FTP server on port 21, so if the packet arrives with a destination port 80, it is for the HTTP server and not for the FTP server. Also the packet has a source port since without such a source port, a server could only have one connection to one IP address at a time. The source port makes it possible for a server to distinguish otherwise identical connections: they all have the same destination port, e.g. port 80, the same destination IP (the IP of the server), and the same source IP, as they all come from the same client, but as they have different source ports, the server can distinguish them from each other. And when the server sends back replies, it will do so to the port the request came from, that way the client can also distinguish different replies it receives from the same server.

An application consists of pair of processes which communicate over the network (client-server pair). These processes send and receive messages, into and from the network through a software interface called socket. Considering the analogy presented in the book "Computer Networking: Top Down Approach". There is a house that wants to communicate with other house. Here, house is analogous to a process, and door to a socket. Sending process assumes that there is a infrastructure on the other side of the door that will transport the data to the destination. Once the message is arrived on the other side, it passes through receiver's door (socket) into the house (process). This illustration from the same book can help you: Sockets are part of transport layer, which provides logical communication to applications. This means that from application's point of view both hosts are directly connected to each other, even though there are numerous routers and/or switches between them. Thus a socket is not a connection itself, it's the end point of the connection. Transport layer protocols are implemented only on hosts, and not on intermediate routers. Ports provide means of internal addressing to a machine. The primary purpose it to allow multiple processes to send and receive data over the network without interfering with other processes (their data). All sockets are provided with a port number. When a segment arrives to a host, the transport layer examines the destination port number of the segment. It then forwards the segment to the corresponding socket. This job of delivering the data in a transport layer segment to the correct socket is called de-multiplexing. The segment's data is then forwarded to the process attached to the socket.

套接字是一种特殊类型的文件句柄,进程使用它从操作系统请求网络服务。 套接字地址是三元组: {protocol, local-address, local-process},其中本地进程由端口号标识。

在TCP/IP套件中,例如:

{tcp, 193.44.234.3, 12345}

会话是两个进程之间的通信链接,从而描述了两者之间的关联。 关联是一个5元组,它完全指定了组成连接的两个进程: {protocol, local-address, local-process, foreign-address, foreign-process}

在TCP/IP套件中,例如:

{tcp, 193.44.234.3, 1500, 193.44.234.5, 21}

可能是一个有效的关联。

半关联是: {protocol, local-address, local-process}

or

{protocol, foreign-address, foreign-process}

它们指定连接的每一半。

半关联也称为套接字或传输地址。也就是说,套接字是可以在网络中命名和寻址的通信端点。 套接字接口是通信协议的几个应用程序编程接口(api)之一。它被设计为一个通用的通信编程接口,最初由4.2BSD UNIX系统引入。虽然还没有标准化,但已经成为事实上的行业标准。

总结

TCP套接字是在特定TCP连接或监听状态的上下文中由IP地址和端口定义的端点实例。

端口是定义服务端点的虚拟化标识符(与服务实例端点又名会话标识符不同)。

TCP套接字不是一个连接,而是一个特定连接的端点。

可以存在到服务端点的并发连接,因为连接由其本地和远程端点标识,从而允许将流量路由到特定的服务实例。

对于给定的地址/端口组合,只能有一个侦听器套接字。

博览会

这是一个有趣的问题,它迫使我重新审视一些我自以为已经完全了解的东西。你可能会认为“插座”这样的名字是不言自明的:选择它显然是为了唤起你插入网线的端点的形象,有很强的功能相似之处。然而,在网络用语中,“套接字”这个词承载了如此多的负担,以至于有必要仔细地重新检查。

在最广泛的意义上,端口是一个入口或出口点。虽然不在网络环境中使用,但法语单词porte的字面意思是门或网关,进一步强调了端口是运输端点的事实,无论您运送数据还是大型钢铁集装箱。

为了本讨论的目的,我将只考虑TCP-IP网络的上下文。OSI模型非常好,但从未完全实现,更不用说在高流量、高压力条件下广泛部署。

IP地址和端口的组合严格地称为端点,有时称为套接字。这种用法起源于RFC793,即最初的TCP规范。

TCP连接由两个端点定义,也就是套接字。

端点(套接字)由网络地址和端口标识符的组合定义。请注意,address/port并不能完全标识一个套接字(稍后会详细介绍)。

端口的目的是区分给定网络地址上的多个端点。您可以说端口是一个虚拟端点。这种虚拟化使单个网络接口上的多个并发连接成为可能。

它是套接字对(4元组) 包括客户端IP地址, 客户端端口号,服务器IP地址, 和服务器端口号)指定 这两个端点唯一 对象中的每个TCP连接 互联网。(TCP-IP插图卷1,W. Richard Stevens)

在大多数c派生语言中,TCP连接是使用Socket类实例上的方法建立和操作的。虽然在更高的抽象级别上操作是常见的,通常是NetworkStream类的实例,但这通常会公开对套接字对象的引用。对于编码器来说,这个套接字对象似乎表示连接,因为连接是使用套接字对象的方法创建和操作的。

在c#中,要建立一个TCP连接(到一个现有的侦听器),首先要创建一个TcpClient。如果您没有指定TcpClient构造函数的端点,它将使用默认值—以某种方式定义本地端点。然后调用Connect 方法。此方法需要描述另一个端点的参数。

所有这些都有点令人困惑,并导致您相信套接字是一个连接,这是胡说八道。在理查德·多尔曼提出这个问题之前,我一直在这个误解中苦苦挣扎。

在进行了大量阅读和思考之后,我现在确信,使用带有两个参数LocalEndpoint和RemoteEndpoint的构造函数的类TcpConnection会更有意义。当本地端点的默认值是可接受的时,您可能会支持单个参数RemoteEndpoint。这在多址计算机上是不明确的,但是可以使用路由表通过选择到远程端点的最短路由的接口来解决这种不明确。

在其他方面,透明度也将得到提高。套接字不能通过IP地址和端口的组合来识别:

[...]TCP demultiplexes incoming segments using all four values that comprise the local and foreign addresses: destination IP address, destination port number, source IP address, and source port number. TCP cannot determine which process gets an incoming segment by looking at the destination port only. Also, the only one of the [various] endpoints at [a given port number] that will receive incoming connection requests is the one in the listen state. (p255, TCP-IP Illustrated Volume 1, W. Richard Stevens)

正如您所看到的,网络服务有许多具有相同地址/端口的套接字,但在特定地址/端口组合上只有一个侦听器套接字,这不仅是可能的,而且很有可能。典型的库实现提供了一个套接字类,该类的实例用于创建和管理连接。这是非常不幸的,因为它引起了混乱,并导致了两个概念的广泛合并。

Hagrawal不相信我(见评论),所以这里有一个真实的例子。我把一个浏览器连接到http://dilbert.com,然后运行netstat -an -p tcp。输出的最后六行包含两个示例,说明地址和端口不足以唯一地标识一个套接字。在192.168.1.3(我的工作站)和54.252.94.236:80(远程HTTP服务器)之间有两个不同的连接。

  TCP    192.168.1.3:63240      54.252.94.236:80       SYN_SENT
  TCP    192.168.1.3:63241      54.252.94.236:80       SYN_SENT
  TCP    192.168.1.3:63242      207.38.110.62:80       SYN_SENT
  TCP    192.168.1.3:63243      207.38.110.62:80       SYN_SENT
  TCP    192.168.1.3:64161      65.54.225.168:443      ESTABLISHED

由于套接字是连接的端点,因此有两个套接字的地址/端口组合为207.38.110.62:80,另外两个套接字的地址/端口组合为54.252.94.236:80。

我认为哈格拉瓦尔的误解源于我对“认同”一词的谨慎使用。我的意思是“完全的,明确的,唯一的识别”。在上面的示例中,有两个端点的地址/端口组合为54.252.94.236:80。如果你只有地址和端口,你没有足够的信息来区分这些套接字。这些信息不足以识别套接字。

齿顶高

RFC793第2.7节第2段说

连接完全由两端的一对套接字指定。一个 本地套接字可能参与到不同外部的多个连接 套接字。

从编程的角度来看,socket的这个定义没有帮助,因为它与socket对象不同,后者是特定连接的端点。对于程序员(这个问题的大多数读者都是程序员)来说,这是一个至关重要的功能差异。

@plugwash提出了一个显著的观察。

最根本的问题是TCP RFC对socket的定义与所有主流操作系统和库所使用的socket的定义相冲突。

根据定义,RFC是正确的。当一个标准库误用术语时,它不会取代RFC。相反,它给该库的用户带来了一种责任负担,即理解两种解释,并小心用词和上下文。如果RFC不一致,则最新的和最直接适用的RFC优先。

参考文献

TCP-IP图解卷1协议,W. Richard Stevens, 1994 Addison Wesley RFC793,信息科学研究所,南加州大学DARPA RFC147,插座的定义,Joel M. Winett,林肯实验室