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


当前回答

似乎有很多答案将socket等同于2台PC之间的连接。我认为这是完全错误的。套接字一直是一台PC上的端点,可能连接也可能不连接-当然我们都在某些时候使用侦听器或UDP套接字*。重要的部分是它是可寻址的和活跃的。向1.1.1.1:1234发送消息不太可能起作用,因为没有为该端点定义套接字。

套接字是特定于协议的-因此,TCP/IP和UDP/IP都使用* (ipaddress:port)的唯一性实现与eg不同。, IPX (Network, Node, and…嗯哼,套接字——但是一个不同的套接字是指一般的“套接字”术语。IPX套接字号相当于IP端口)。但是,它们都提供了唯一的可寻址端点。

由于IP已成为主导协议,端口(在网络术语中)已成为UDP或TCP端口号的同义词——后者是套接字地址的一部分。

UDP is connection-less - meaning no virtual circuit between the 2 endpoints is ever created. However, we still refer to UDP sockets as the endpoint. The API functions make it clear that both are just different type of sockets - SOCK_DGRAM is UDP (just sending a message) and SOCK_STREAM is TCP (creating a virtual circuit). Technically, the IP header holds the IP Address, and the protocol on top of IP (UDP or TCP) holds the port number. This makes it possible to have other protocols (eg. ICMP that have no port numbers, but do have IP addressing information).

其他回答

总结

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,林肯实验室

套接字地址是一个IP地址和端口号

123.132.213.231         # IP address
               :1234    # port number
123.132.213.231:1234    # socket address

当两个套接字绑定在一起时,就发生了连接。

Socket是软件抽象的网络端点,用作应用程序的接口。在Java、c#中,它用对象表示,在Linux、Unix中,它是一个文件。

Port只是一个套接字的属性,如果你想建立一个通信,你必须指定。要从套接字接收数据包,必须将其绑定到特定的本地端口和网卡(具有本地IP地址)或所有网卡(在绑定调用中指定INADDR_ANY)。要发送数据包,必须指定远端套接字的端口和IP。

In a broad sense, Socket - is just that, a socket, just like your electrical, cable or telephone socket. A point where "requisite stuff" (power, signal, information) can go out and come in from. It hides a lot of detailed stuff, which is not required for the use of the "requisite stuff". In software parlance, it provides a generic way of defining a mechanism of communication between two entities (those entities could be anything - two applications, two physically separate devices, User & Kernel space within an OS, etc)

端口是端点标识符。它区分一个端点和另一个端点。在网络级别,它将一个应用程序与另一个应用程序区分开来,以便网络堆栈可以将信息传递给适当的应用程序。

端口和插座可以比作银行分行。

“银行”的门牌号与IP地址类似。 银行有不同的部分,比如:

储蓄帐务部 个人贷款部 房屋贷款部 投诉部门

因此,1(储蓄账户部)、2(个人贷款部)、3(住房贷款部)和4(申诉部)是端口。

现在让我们假设你要开一个储蓄账户,你去了银行(IP地址),然后你去了“储蓄账户部门”(端口号1),然后你遇到了在“储蓄账户部门”工作的一名员工。让我们称他为SAVINGACCOUNT_EMPLOYEE1,用于开户。

SAVINGACCOUNT_EMPLOYEE1是套接字描述符,因此可能存在 SAVINGACCOUNT_EMPLOYEE1到SAVINGACCOUNT_EMPLOYEEN。这些都是套接字描述符。

同样地,其他部门将有员工在他们之下工作,他们类似于插座。