在支持多个选项卡的 Web 浏览器中,例如 Firefox,指向不同网站域的不同选项卡是否对每个域使用专用端口?
或者浏览器是否使用单个端口来管理所有选项卡以及所有域?
答案1
浏览器是否使用不同的端口连接不同的网站?
是的,他们确实这么做。
下面是一个示例,显示我在 Windows 7 上的当前 Firefox 连接(我打开了 9 个选项卡):
笔记:
可以看到本地端口都是不同的。
远程端口通常为 80(HTTP)、443(HTTPS)或 8080(HTTP 备用)。
- 许多其他端口用于托管 Web 服务器。
HTTP
搜索TCP 和 UDP 端口号列表对于其中一些人来说。
- 许多其他端口用于托管 Web 服务器。
下面描述了渲染网页的完整过程。请特别参阅步骤 5、6、13 和 15(以粗体显示):
一般来说,呈现单个网页需要使用多个连接,但并非所有连接都指向同一个远程地址。
这是因为网页通常包含托管在其他地方的资源(javascript 文件等)。
多个连接到相同的网站(例如 stackoverflow.com)也有不同的本地端口(因为它们是不同选项卡中呈现不同页面的单独连接)。
渲染网页——分步说明
笔记:
- 步骤 5、6、13 和 15(以粗体显示)与问题直接相关。
你有没有想过,当你上网时会发生什么?事情并没有看上去那么简单:
- 您在首选浏览器的地址栏中输入 URL。
- 浏览器解析 URL 以查找协议、主机、端口和路径。
- 它形成一个 HTTP 请求(这很可能是协议)
- 为了到达主机,它首先需要将人类可读的主机转换为 IP 号码,并通过在主机上进行 DNS 查找来实现
- 然后需要在用户的计算机和该 IP 号码的指定端口(通常是 80 端口)上打开一个套接字
- 当连接打开时,HTTP 请求将发送到主机
- 主机将请求转发到配置为监听指定端口的服务器软件(通常是 Apache)
- 服务器检查请求(通常仅检查路径),并启动处理请求所需的服务器插件(对应您使用的服务器语言,PHP、Java、.NET、Python?)
- 插件可以访问完整的请求,并开始准备 HTTP 响应。
- 为了构造响应,最有可能的是访问数据库。根据请求路径(或数据)中的参数进行数据库搜索
- 来自数据库的数据与插件决定添加的其他信息一起组合成一串长文本(可能是 HTML)。
- 该插件将该数据与一些元数据(以 HTTP 标头的形式)相结合,并将 HTTP 响应发送回浏览器。
- 浏览器收到响应,并解析响应中的 HTML(95% 的概率是错误的)
- DOM 树由损坏的 HTML 构建而成
- 对于在 HTML 源代码中找到的每个新资源(通常是图像、样式表和 JavaScript 文件),都会向服务器发出新请求。返回步骤 3 并对每个资源重复此操作。
- 样式表被解析,每个样式表的渲染信息被附加到 DOM 树中的匹配节点
- Javascript 被解析并执行,DOM 节点被移动,样式信息也随之更新
- 浏览器根据 DOM 树和每个节点的样式信息将页面渲染到屏幕上
- 您在屏幕上看到该页面
- 您会因为整个过程太慢而感到烦恼。
答案2
每次连接到网站时都会使用不同的套接字,对于普通 HTTP,默认目标 TCP 端口为 80,对于 HTTPS,默认目标 TCP 端口为 443。为了使套接字唯一,源 IP 地址、源 TCP 端口、目标 IP 地址和目标 TCP 端口的组合必须不同。
如果您从同一台计算机与同一网站建立多个连接(假设该网站仅使用 1 个 IP 地址),则必须使用不同的源 TCP 端口。这样,每个连接都是唯一的。
但是,需要注意的是,从 HTTP 1.1 开始,所有连接在给定的时间段内都是持久的(除非另有声明)。这意味着,如果请求来自同一网站的多个资源(例如 css/js 文件),您的浏览器可以重复使用同一个连接。如果您的浏览器中有同一网站的多个实例,这也适用。
如果您使用的是 Windows,该netstat -no -p TCP
命令将显示所有活动的 TCP 套接字及其对应的进程 ID,包括您的浏览器的进程 ID:
如果您使用的是 Unix/Linux(在本例中为 Debian),则可以使用netstat -ntp
或ss -t
命令:
答案3
至于不同网站的标签,TCP 中没有任何内容要求本地端口不同,只要元组{本地 IP,本地端口,目标 IP,目标端口}是唯一的。对于同一个网站的标签,情况要复杂得多。
浏览器与任何其他客户端软件一样,对同一目标的每个传出连接使用不同的本地端口。通常,它会与任何给定网站建立多个连接,以获取嵌入的资源,例如图像、CSS、JavaScript 等。它还会将这些连接集中起来以供重复使用。
目前还无法确定同一个网站的不同标签是否会使用不同的连接,因为 (a) 通常每个选项卡没有单个连接,并且 (b) 根据时间和身份验证,连接可以在选项卡之间重复使用;并且由于无法识别连接,因此也无法识别本地端口。
答案4
我在 MacOS 12.3.1 上使用以下浏览器进行了测试:Chrome 109.0.5414.119 Safari 15.4 (17613.1.17.1.13)
我打开了 2 个选项卡,并浏览到我用 Python 运行的简单本地服务器。该服务器有 2 个工作程序。
结果是:
用例 1 - 浏览至http://127.0.0.1:5000/
铬合金
2 个选项卡请求相同的 URL,例如 127.0.0.1:5000/?value=1,按顺序运行。当第一个选项卡结束时,第二个选项卡开始。这意味着 2 个选项卡都在 10 秒后完成。无论选项卡位于同一窗口还是不同窗口,都没有关系。
两个选项卡使用相同的端口。
如果选项卡访问不同的 URL,127.0.0.1:5000/?value=1 或 127.0.0.1:5000/?value=2,则选项卡将使用不同的端口并行运行,并在 5 秒后完成。
苹果浏览器
2 个请求相同 URL 的选项卡使用不同的端口并行运行。这些选项卡位于相同或不同的窗口中并不重要。这些选项卡是否访问相同的 URL 并不重要。这些选项卡使用不同的端口并行运行,5 秒后完成。
The FastAPI, Uvicorn server
import asyncio
from fastapi import FastAPI
import uvicorn
from datetime import datetime
app = FastAPI()
class MyClass:
value: str = 'a'
@app.get("/")
async def root(value: int):
MyClass.value = MyClass.value + 'b'
start = datetime.now().strftime("%H:%M:%S")
await asyncio.sleep(5)
end = datetime.now().strftime("%H:%M:%S")
return {
"start": start,
"end": end,
"value": value
}
@app.get("/root2")
async def root2():
MyClass.value = MyClass.value + 'c'
start = datetime.now().strftime("%H:%M:%S")
await asyncio.sleep(5)
end = datetime.now().strftime("%H:%M:%S")
return {
"start": start,
"end": end,
"value": MyClass.value
}
if __name__ == "__main__":
uvicorn.run("main:app", host="127.0.0.1", port=5000, log_level="info", workers=2)