混淆端口和套接字的区别

7

好的,当我尝试研究IP地址、端口和套接字时,我得到了以下内容:

IP地址用于在网络上映射到不同的设备。

端口号用于访问主机上特定的应用程序。

套接字是两者的组合。

我不理解的是,如果端口将您连接到特定的应用程序,那么每个应用程序应该只有一个端口号,对吗?但例如端口80用于HTTP,因此如果一个应用程序正在使用该端口,则它正在侦听HTTP请求,对吗?那么如果有多个人尝试访问它会发生什么?套接字和端口让我非常困惑..


2
请查看此问题:https://dev59.com/s3VC5IYBdhLWcg3w51dv?rq=1 - Innot Kauker
这是关于编程的内容:有一个监听套接字(定义了端口),但你那边的连接套接字可能会改变(未定义端口,随机的)。需要提醒的是:一个应用程序当然可以使用更多的端口。比如FTP:21号端口是命令端口,而20号端口是数据端口。 - Marc Wittmann
@InnotKauker,尽管它得到了高票支持,但那个答案有点不准确。它还使用了不必要复杂的语言来解释一些非常简单的东西。我正在这个帖子上写一个更加“平易近人”的答案... - Alex D
3个回答

6
套接字是软件中使用的抽象概念,使程序员更容易通过网络发送和接收数据。它们是一种接口,您可以在应用程序级别代码中使用它们来访问操作系统和语言运行时提供的底层网络协议实现。
TCP协议、IP协议和其他流行的网络协议本身并没有任何关于“套接字”的概念。“套接字”是TCP/IP实现者想出来的一个概念。
那么,“套接字”的概念是什么?基本上,它是一个对象,您可以向其写入数据,也可以从中读取数据。“打开”一个套接字意味着在程序内存中创建一个这样的对象。您还可以“关闭”套接字,这意味着释放该对象在后台使用的任何系统资源。
某些类型的套接字可以“绑定”到本地和远程地址,您可以将其视为在套接字对象上设置一些数据字段或属性。这些字段的值会影响从套接字读取或写入时发生的情况。
在Unix中,有各种类型的套接字。如果您“打开”一个TCP套接字,“绑定”到本地和远程地址(和端口),并将一些数据写入其中,则您的库/操作系统将将该数据打包成TCP段并通过与您“绑定”套接字的本地地址匹配的任何网络接口发送出去。如果您“打开”一个IP套接字并将一些数据写入其中,则该数据将被打包成IP数据包(没有添加TCP头),然后发送出去。如果您打开一个“原始”的链路级套接字并写入其中,则数据将作为链路级帧的有效负载发送,减去IP和TCP头。还有“Unix域套接字”。如果您打开其中之一并写入其中,则该数据将直接通过系统内存传递到同一台机器上的另一个进程。
因此,尽管它们通常用于非OO语言,如C,但套接字是OO语言所称的“多态性”的完美例子。如果您曾经在向某人解释“多态性”时遇到麻烦,只需教他们关于网络套接字即可。
“端口”是完全不同的概念。“端口”的想法是内置在TCP和其他传输协议中的。
其他人可能会给出更高深、也许更技术上准确的“端口”定义。这里是一个非常基础的定义:
“端口”是出现在TCP段的TCP头中的一个数字。(或UDP段上的UDP头。)
只是一个数字。没有多余的东西,也没有少的东西。
如果您正在使用基于“套接字”的接口进行网络编程,则该数字的重要性在于您的每个TCP或UDP套接字都具有“本地端口”属性和“远程端口”属性。正如我之前所说,设置这些属性称为“绑定”。
如果您的套接字的“本地端口”属性绑定到80,则您发送的所有TCP段都将在“发送方端口”头中具有“80”。然后,当其他人回复您的消息时,他们将在其“目标端口”头中放置“80”。
此外,如果您的套接字绑定到本地端口80,则当数据从其他位置到达,寻址到您的端口80时,操作系统将将其传递给您的应用程序进程而不是其他任何进程。然后,当您尝试从套接字读取时,该数据将被返回。
显然,操作系统需要知道每个套接字绑定到哪个端口。因此,在“绑定”时必须进行系统调用。如果您的程序没有足够的特权运行,则操作系统可能会拒绝让您绑定到某个端口。然后,根据您使用的语言,您的网络库将抛出异常或返回错误代码。
有时,操作系统可能会拒绝让您绑定到某个端口,不是因为您没有正确的特权,而是因为另一个进程已经绑定到它。 但是,这就是其他答案所犯的错误,如果在打开套接字时设置了某些标志,您的操作系统可能允许多个套接字绑定到同一本地地址和端口。
您仍然不知道“侦听”和“连接”的套接字是什么。但是,一旦您理解了上述内容,那只是一个小跳跃。 上述内容解释了我们今天所称的“套接字”和我们所称的“端口”之间的区别。仍然可能不清楚的是:为什么我们需要做出这种区别? 你确实让我思考了(谢谢!)。我们可以称为“套接字”的软件抽象称为“端口”,以便您在调用socket_recv时调用port_recv吗?
如果您只对TCP和UDP感兴趣,可能会起作用。请记住,“套接字”抽象不仅适用于TCP和UDP。它还适用于其他网络协议,以及用于在同一台机器上进行进程间通信。
另一方面,TCP套接字不仅映射到端口。 “已连接”TCP套接字映射到本地IP地址,本地端口,远程地址,和远程端口。它还具有其他相关数据,包括各种标志,发送和接收缓冲区,用于传入/传出数据流的序列号以及用于拥塞控制(速率限制)等各种其他变量。该数据不仅属于本地端口。
可以通过同一“端口”同时进行数千个TCP连接。每个连接都有其自己的相关数据,封装该每个连接数据的软件对象是“TCP套接字”。
即使你只使用TCP/UDP,即使你每次只有一个进程使用任何给定的本地端口,即使你每次只有一个连接通过每个本地端口,我认为“套接字”抽象仍然是有意义的。如果我们只称套接字为“端口”,那么在这一个词中会有更多的含义混淆。对于太多含义重叠的单词进行重复使用会阻碍沟通。
“端口”是应用程序进程的传输协议级别标识符。“套接字”是软件中用于发送/接收从/到这些标识符地址的消息的对象。
区分“我的地址”和“发送来自我的信件”的东西是有用的区分。“我的地址”只是一个标签。一个标签不是像发送数据这样的活跃物体。给“用于发送数据的东西”赋予与表示“数据标记的发件人地址”不同的名称是有逻辑的。

那么你为什么不能只是向端口号“写数据”呢?为什么要有套接字?我不理解它们之间的区别,它们都可以标识应用程序进程... - user3843164
非常有趣的概念性问题!我已经添加了更多信息,这可能会让你更清楚。 - Alex D
哦,好的,所以如果一个应用程序进程有多个传入连接,即使使用相同的端口因为它是一个应用程序,你需要套接字来区分不同的连接,对吧? - user3843164
@user3843164,如果你正在使用TCP,那是正确的。除了每个TCP连接通过相同的端口需要一个套接字外,你还需要一个“监听”套接字来接受新的连接。 - Alex D

0

当应用程序(例如像Apache或Nginx这样的Web服务器)监听某个端口(比如80端口)时,它会创建所谓的监听套接字。

当有客户端连接时,这个监听套接字会被更新(可以通过selectpoll API来观察),然后我们的应用程序会创建通信套接字。这个套接字由元组(src_addr, src_port, dst_addr, dst_port)唯一标识——很可能许多客户端将具有完全相同的(dst_addr, dst_port)组合。

然后我们的Web服务器可以通过该通信套接字进行通信,以提供Web页面并最终关闭此套接字。当许多客户端同时到来时,Web服务器可以为每个客户端创建线程/进程(Apache模型),或逐个服务所有套接字(Nginx模型)。

请注意,在这种情况下,每个端口只能存在一个监听套接字,多个应用程序不能绑定到相同的端口(如80端口)。但是,拥有许多通信套接字是完全可以的(有些人报告成功处理超过一百万个并发请求)。


0
每次在监听状态下接受套接字连接(例如在端口80上),您都会得到一个代表连接的处于已建立状态的新套接字。
在客户端,每当与该地址和端口建立新连接时(正在连接的新套接字),操作系统将在您的一侧分配一个随机端口。
例如,如果您进行两次连接:
your-host:22482 <---> remote-host:80
your-host:23366 <---> remote-host:80

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接