这个问题已经在这里有一个答案:
- 本港口的变化,当一个服务器接受一个TCP连接? 3个回答
我理解的端口是如何工作的基本知识。 不过,我不明白的是多个客户端如何能够同时连接到说80端口。我知道每个客户都有一个唯一的(他们的机器)端口。 服务器是否从一个可用的端口给客户回信,并简单陈述的答复从80来的? 这是如何运作的?
这个问题已经在这里有一个答案:
我理解的端口是如何工作的基本知识。 不过,我不明白的是多个客户端如何能够同时连接到说80端口。我知道每个客户都有一个唯一的(他们的机器)端口。 服务器是否从一个可用的端口给客户回信,并简单陈述的答复从80来的? 这是如何运作的?
首先,一个“口”只是一个数字。 所有的“连接到端口”真正代表是在其“目的港”头字段指定数量的数据包。
现在,有两个答案你的问题,一个有状态的协议和一个无状态协议。
对于无状态协议(即UDP),是没有问题的,因为“关系”是不存在的 - 多的人可以将数据包发送到同一个端口,他们的数据包以任何顺序到达。 没有人是曾经在“连接”状态。
对于状态协议(如TCP),连接是通过包括源和目的端口和源和目的地IP地址的四元组来标识。 所以,如果两个不同的机器连接到第三机器上的相同的端口,有两种不同的连接,因为该来源IP不同。 如果在同一台机器(或两个NAT后面或以其他方式共享相同的IP地址)连接两次,以一个单一的远端,所述连接由源端口(通常是随机高编号端口)来区分。
简单地说,如果我连接到同一台服务器的两倍,从我的客户,这两个连接将有来自Web服务器的我的观点和目的端口不同的源端口。 所以,没有歧义,即使这两个连接具有相同的源和目的IP地址。
端口复用的IP地址,使得不同的应用程序可以在同一个IP地址/协议对听的方式。 除非应用程序定义它自己的更高级别的协议,也没有办法来复用的端口。 如果使用相同的协议的两个连接同时具有相同的源和目的地IP地址和相同的源和目的地端口,它们必须是相同的连接。
重要:
我很抱歉地说,从“Borealid”的反应是不准确的,有点不正确 - 首先是没有关系有状态或无国籍回答这个问题,最重要的元组插座的定义不正确。
首先请记住以下两个规则:
插座的主键:一个套接字被标识{SRC-IP, SRC-PORT, DEST-IP, DEST-PORT, PROTOCOL}
不是{SRC-IP, SRC-PORT, DEST-IP, DEST-PORT}
-协议是一个套接字定义的一个重要组成部分。
OS过程和插座映射:一个进程可以使用(可以打开/可收听)多个插槽,这可能是显而易见的许多读者相关联。
实施例1:连接到相同的服务器端口两个客户端装置: socket1 {SRC-A, 100, DEST-X,80, TCP}
和socket2{SRC-B, 100, DEST-X,80, TCP}
这意味着主机A连接到服务器X的端口80和另一个主机B也连接到同一台服务器X相同的80端口现在,服务器如何处理这两个插槽取决于如果服务器是单线程还是多线程(我会解释这个版本)。 最重要的是,一台服务器可以同时监听多个插座。
要回答这个职位的原题:
无论状态或无状态协议,两个客户端可以连接到同一台服务器端口,因为每个客户端,我们可以指定一个不同的套接字(如客户端IP肯定会有所不同)。 同一个客户端也可以连接到同一台服务器端口两个插槽-因为这种插座相差SRC-PORT
。 随着平心而论,“Borealid”基本上提到的相同的正确答案,但参考无状态/全是那种不必要/混乱。
要回答的服务器是如何知道回答的套接字问题的第二部分。 首先明白,那是听同一端口,一个服务器进程,可能有不止一个插槽(可从同一客户端或不同的客户端)。 现在只要一台服务器知道哪个请求与套接字关联,它可以随时到相应的客户端使用相同的插座回应。 因此,服务器永远不需要在其自己的节点不是哪个客户端最初试图绑定连接原来打开另一个端口。 如果一个套接字绑定后的任何服务器分配不同的服务器端口,那么在我看来,服务器浪费其资源和必须需要客户端绑定再次连接到指定的新端口。
多一点的完整性:
例2:这是一种可以在服务器的两个不同的进程收听同一端口非常有趣的问题。 如果不考虑协议作为参数定义插座一个,那么答案是否定的。 主动是这样,因为我们可以说,在这种情况下针对单个客户端试图连接到服务器的端口将不会有任何机制来提这两个监听进程的客户打算。 这是由规则(2)主张的同一个主题。 然而这是错误的答案,因为“协议”也插座定义的一部分。 因此,在同一个节点两个过程只能如果它们使用不同的协议收听同一个端口。 例如,两个不相关的客户端(说一个是使用TCP和另一个是使用UDP)可以结合连接和通信到相同的服务器节点,并在相同的端口,但它们必须由两种不同的服务器进程来服务。
服务器类型-单个与多个:
当一个服务器工作过程听一个端口,这意味着多个套接字可以同时连接,并与在同一服务器进程进行通信。 如果一台服务器只使用一个子进程,为所有插座,则服务器被称为单进程/线程,如果服务器使用许多子过程由一个子进程,则服务器被称为多服务于每个插座进程/线程服务器。 注意服务器的类型是不考虑一台服务器可以/应该总是使用相同的初始套接字来响应(不需要分配另一个服务器端口)。
建议书 ,如果你能在两卷的其余部分。
关于父/子进程的注记(响应于查询“伊万亚历簇簇”的/注释)
只要我提到的关于两个进程的任何概念说A和B,认为它们不是由父子关系相关。 OS的(特别是UNIX)设计允许一个子进程来继承父母的所有文件描述符(FD)。 因此,所有的插座(在UNIX操作系统一样,也FD的一部分)的处理的听,可以被更多的过程A1,A2,...只要被监听,因为它们是通过父子关系相关A.但是,一个独立的过程B(即,具有没有父 - 子关系,以A)不能听同一插座。 另外,还要注意的是,不允许两个独立的过程来听同一插座的这个规则在于操作系统(或其网络库)上迄今为止它是由大多数操作系统的服从。 然而,我们可以创建自己的操作系统,可以很好地违反此限制。
所以,当一个服务器监听TCP端口上的入站连接,会发生什么? 例如,假设你有端口80上的Web服务器让我们假设你的电脑有24.14.181.229的公网IP地址,并尝试连接到您的IP地址为10.1.2.3的人。 此人可以通过打开TCP套接字连接24.14.181.229:80给你。 够简单。
直觉(错误地),大多数人认为它看起来是这样的:
Local Computer | Remote Computer
--------------------------------
<local_ip>:80 | <foreign_ip>:80
^^ not actually what happens, but this is the conceptual model a lot of people have in mind.
这是直观的,因为从客户的角度来看,他有一个IP地址,并连接到服务器IP地址:端口。 由于客户端连接到端口80,那么他的端口必须是80吗? 这是想一个明智的做法,但实际上没有发生什么变化。 如果是是正确的,我们可能只会%的外国IP地址一个用户。 一旦远程计算机连接,那么他就霸占80端口80端口的连接,并没有其他人可以连接。
有三两件事必须理解:
1)在服务器上,一个进程正在侦听端口。 一旦它得到一个连接,它交给它给另一个线程。 通信从来没有猪的侦听端口。
2.)连接被唯一地标识由OS通过以下的5元组:(本地IP,本地端口,远程IP,远程端口,协议)。 如果在元组的任何元件是不同的,那么这是一个完全独立的连接。
3.)当客户端连接到服务器时,它选择一个随机的,未使用高阶源端口 。 这样一来,单个客户端最多可以有64K〜连接到服务器对于同一个目的端口。
所以,这是真的,当一个客户端连接到一台服务器有什么被创建:
Local Computer | Remote Computer | Role
-----------------------------------------------------------
0.0.0.0:80 | <none> | LISTENING
127.0.0.1:80 | 10.1.2.3:<random_port> | ESTABLISHED
首先,让我们使用netstat来看看这台计算机上发生的事情。 我们将使用端口500,而不是80(因为东西一大堆的端口80上发生的事情,因为它是一种常见的端口,但在功能上却不会有所作为)。
netstat -atnp | grep -i ":500 "
正如预期的那样,输出是空白。 现在让我们开始的web服务器:
sudo python3 -m http.server 500
现在,这里是netstat的重新运行的输出:
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:500 0.0.0.0:* LISTEN -
所以现在有一个过程,积极倾听(状态:LISTEN)端口500的本地地址为0.0.0.0,这是“监听所有”的代码。 一个容易犯的错误是将监听地址127.0.0.1,这将只接受来自当前计算机的连接。 因此,这不是一个连接,这只是意味着一个进程请求绑定()到端口的IP,并且这个过程是负责处理该端口的所有连接。 这暗示这样的限制,即只能有一个端口上的每台计算机监听一个进程(也有方法可以解决,使用复用,但是这是一个复杂得多的话题)。 如果一个Web服务器上的80端口监听,它不能与其他网络服务器的端口。
所以,现在,让我们的用户连接到我们的机器:
quicknet -m tcp -t localhost:500 -p Test payload.
这是一个简单的脚本( https://github.com/grokit/dcore/tree/master/apps/quicknet )打开一个TCP套接字,(在这种情况下,“测试有效载荷。”)发送有效载荷,等待几秒钟和断开。 netstat的同时再次发生这种情况做显示以下内容:
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:500 0.0.0.0:* LISTEN -
tcp 0 0 192.168.1.10:500 192.168.1.13:54240 ESTABLISHED -
如果您与其他客户端连接和netstat再做一次,您将看到以下内容:
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:500 0.0.0.0:* LISTEN -
tcp 0 0 192.168.1.10:500 192.168.1.13:26813 ESTABLISHED -
...也就是说,客户端使用另一个随机端口进行连接。 所以从来没有IP地址之间的混淆。
通常情况下,对于每一个客户端连接服务器叉一个子进程与客户端(TCP)进行通信。 父服务器把手拿开子进程建立的套接字通信返回给客户端。
当您从您的孩子的服务器将数据发送到一个插座,在操作系统的TCP协议栈建立一个信息包要回客户端,并设置了“从端口”为80。
多个客户端可以连接到服务器上的同一个端口(比如80),因为在服务器端,创建套接字 ,并结合后(设置本地IP和端口) 听被称为它告诉OS接受传入连接在插座上。
当客户端试图连接到服务器的80端口,调用accept调用服务器插槽上。 这为客户端试图连接,同样新的套接字将使用同一端口80后续客户端创建一个新的套接字。
斜体字是系统调用。
参考
http://www.scs.stanford.edu/07wi-cs244b/refs/net2.pdf