Google 会为它收到的每个请求打开多少个套接字?

Posted

技术标签:

【中文标题】Google 会为它收到的每个请求打开多少个套接字?【英文标题】:How many sockets do Google open for every request it receives? 【发布时间】:2014-09-12 08:32:06 【问题描述】:

以下是我最近在一家知名网络软件公司的面试经历。我被问到有关互连 TCP 级别和 Web 请求的问题,这让我很困惑。我真的很想知道专家对答案的意见。这不仅是关于面试,而且是关于网络如何工作(或应用层和传输层如何串扰,如果有的话)的基本理解。

    采访者:告诉我在幕后发生的过程 我打开浏览器并在其中输入google.com

    :发生的第一件事是创建了一个套接字,它是 由SRC-IP, SRC-PORT, DEST-IP, DEST-PORT, PROTOCOL 标识。这 SRC-PORT number 是浏​​览器给出的随机数。通常是 TCP/IP 连接协议(建立三次握手)。现在 客户端(我的浏览器)和服务器(谷歌)都准备好处理 要求。 (TCP 连接已建立)。

    采访者:等等,名字解析什么时候发生?

    :是的,对不起。它应该在创建套接字之前发生。 DNS 名称解析首先发生以获取 Google 的 IP 地址 到达。

    采访者:是否为 DNS 名称解析创建了套接字?

    :嗯,其实我也不知道。但我所知道的 DNS 名称解析是 无连接的。也就是说,它不是 TCP,而是 UDP。只有一个 请求-响应循环发生。 (所以有一个为 DNS 创建的新套接字 名称解析)。

    面试官google.com 对其他人的其他请求开放 客户。与 Google 阻止建立连接也是如此 其他用户?

    :我不确定 Google 是如何处理这个问题的。但是在典型的插座中 通信,它在最小程度上阻塞。

    采访者:您认为这可以如何处理?

    :我猜这个进程会派生一个新线程并创建一个套接字来处理我的 要求。从现在开始,我的套接字端点与 Google 就是这个子套接字。

    采访者:如果是这样,这个子套接字的端口号是多少? 与父级不同?

    Me:父套接字在 80 处监听来自的新请求 客户。孩子必须在不同的端口号上监听。

    采访者:自从你的目标端口号改变后,你的 TCP 连接是如何保持的。 (即 Google 数据包中发送的 src-port 号)?

    我: 我作为客户端看到的 dest-port 始终是 80。当 一个响应被发回,它也来自端口 80。我猜是操作系统/ 父进程在发送回源端口之前将源端口设置回 80 发帖。

    面试官:你的套接字连接建立了多长时间 谷歌?

    :如果我在一段时间内没有提出任何要求, 主线程关闭其子套接字和来自的任何后续请求 我会像一个新客户一样。

    采访者:不,Google 不会为 你。它处理您的请求并正确丢弃/回收套接字 离开。

    采访者:虽然 Google 可能有很多服务器要服务 请求时,每台服务器只能在 80 端口打开一个父套接字。访问 Google 网页的客户端数量必须大于其拥有的服务器数量。这通常是如何处理的?

    :我不确定这是如何处理的。我看到了唯一的办法 work 会为它收到的每个请求生成一个线程。

    采访者:您认为 Google 处理这件事的方式与 任何银行网站?

    Me:在 TCP-IP 套接字级别,应该是 相似的。在请求级别,由于会话稍有不同 维护以在对银行网站的请求之间保持状态。

如果有人能对每一点给出解释,对很多网络初学者来说会很有帮助。

【问题讨论】:

浏览器很可能实际上并没有请求特定的源端口,而是将其留给 O/S 寻找空闲端口,因为浏览器不尝试提供任何内容。而DNS解析也由O/S处理;它首先检查主机文件(在 Lunix 上,即 /etc/hosts,在 Winblows 中,这是 System32/drivers 下的某个文件)。 我能想到的回答这个问题的最简单方法是关闭所有不必要的联网应用程序,启动wireshark,然后观看奇迹发生。根据您的 IP 进行过滤。 "告诉我当我打开浏览器并在其中输入 google.com 时发生的幕后过程。"该过程的大部分将由wireshark记录,并且“wireshark无法与我的ISP合作”......嗯? Wireshark 是一个本地程序,它被动地监视通过您的 NIC 的流量。您的 ISP 不仅不知道它正在运行,而且您的 ISP 根本无法知道您是否正在对通过您的机器的流量进行数据包捕获。你可以使用wireshark,或者fiddler,或者只是tcpdump或者ethereal,或者etherape... 你对面试官问题的回答都没有考虑到客户端机器可能有多个 NIC 需要检查到 Google 的合适路由,或者可能首先在本地执行 DNS(主机文件) 然后通过每个 NIC 的网关(因此路由器可以执行 LAN 地址的 DNS),最终将到达 ISP 网关并通过 ISP/Internet DNS 服务器迭代工作,直到最终得到明确的答案。 DNS 本身同时支持 TCP 和 UDP(是的,DNS 包含一个套接字,但通常不是您创建的,除非您发送自己的 DNS 查询)... 一旦你连接到谷歌,查询它并不会阻止其他用户。任何有价值的 Web 服务器都不会是单线程的。众所周知,Google 将custom-made software 用于其网络服务器和其他在线系统,因此任何人都可以猜测它如何实现并发请求的处理,但它必须处理的庞大流量绝对不会是同步/阻塞的。 【参考方案1】:

对于第 6 点,我是这样理解的:如果端到端连接的两端与另一个套接字的两端相同,则确实无法区分两个套接字,但如果单端是与其他插座不一样,那么很容易区分两者。由于源端口不同,因此无需来回切换目标端口 80(默认)。

【讨论】:

【参考方案2】:

Google 会为它收到的每个请求打开多少个套接字?

这个问题实际上并没有出现在面试中,但它在你的标题中,所以我会回答它。谷歌根本不打开任何套接字。您的浏览器会这样做。 Google接受连接,以新套接字的形式,但我不会将其描述为“打开”它们。

采访者:告诉我当我打开浏览器并在其中输入 google.com 时幕后发生的过程。

我:发生的第一件事是创建一个由 SRC-IP, SRC-PORT, DEST-IP, DEST-PORT, PROTOCOL 标识的套接字。

没有。 连接由元组标识。套接字是连接的端点。

SRC-PORT 号是浏览器给出的随机数。

没有。由操作系统决定。

通常是 TCP/IP 连接协议(建立三路握手)。现在客户端(我的浏览器)和服务器(谷歌)都准备好处理请求了。 (TCP连接建立)

面试官:等等,什么时候解析名字?

我:是的,对不起。它应该在创建套接字之前发生。 DNS 名称解析首先发生以获取 google 的 IP 地址。

采访者:是否为 DNS 名称解析创建了套接字?

我:嗯,我其实不知道。但我所知道的 DNS 名称解析是无连接的。那不是TCP,而是UDP。只发生一个请求-响应周期。 (因此是为 DNS 名称解析创建的新套接字)。

任何合理实现的浏览器都会将整个事情委托给操作系统的 Sockets 库,其内部功能取决于操作系统。在访问 DNS 服务器之前,它可能会查看内存缓存、文件、数据库、LDAP 服务器等几件事,这可以通过 TCP 或 UDP 完成。这不是一个好问题。

采访者:google.com 对其他客户的其他请求开放。那么与谷歌建立连接是否会阻止其他用户?

我:我不确定谷歌如何处理这个问题。但是在典型的套接字通信中,它在最小程度上是阻塞的。

又错了。它与谷歌的关系不大。 TCP 服务器对每个接受的连接都有一个单独的套接字,任何合理构建的 TCP 服务器都完全独立地处理它们,无论是通过多线程、多路复用/非阻塞 I/O 还是异步 I/O。它们不会互相阻挡。

采访者:你认为这可以如何处理?

我:我猜这个进程会派生一个新线程并创建一个套接字来处理我的请求。从现在开始,我与谷歌通信的套接字端点就是这个子套接字。

创建线程,而不是“分叉”。分叉一个进程会创建另一个进程,而不是另一个线程。套接字不是“创建”的,而是被接受的,这通常会在线程创建之前。它不是一个“子”套接字。

采访者:如果是这样的话,这个child socket的端口号是不是和parent不一样?

我:父套接字在 80 处监听来自客户端的新请求。孩子必须在不同的端口号上监听。

又错了。接受的套接字使用与侦听套接字相同的端口号,接受的套接字根本不是“侦听”,它是接收发送。

面试官:自从你的 Dest-port 号码改变后,你的 TCP 连接是如何保持的。 (也就是google包发送的src-port号)?

我:我作为客户端看到的 dest-port 始终是 80。当请求被发回时,它也来自端口 80。我猜操作系统/父进程在发送之前将 src 端口设置回 80回帖。

本题旨在探究您之前的错误答案。你继续你的错误答案仍然是错误的。

面试官:你和google建立socket连接多久了?

我:如果我在一段时间内没有发出任何请求,主线程将关闭它的子套接字,我的任何后续请求都会像一个新客户端一样。

又错了。您对 Google 的线程一无所知,更不用说哪个线程关闭了套接字。任何一端都可以随时关闭连接。很可能服务器端会打败你,但它不是一成不变的,如果有线程可以做到这一点,也不是一成不变的。

面试官:不,谷歌不会为你保留一个专门的子套接字。它会处理您的请求并立即丢弃/回收套接字。

这里面试官错了。他似乎没有听说过 HTTP keep-alive,或者它是 HTTP 1.1 中的默认设置。

面试官:虽然google可能有很多服务器来处理请求,但是每台服务器只能在80端口打开一个父socket。访问google网页的客户端数量必须大于他们拥有的服务器数量。这通常是如何处理的?

我:我不确定这是如何处理的。我认为它可以工作的唯一方法是为它收到的每个请求生成一个线程。

这里你根本没有回答这个问题。他正在寻找有关负载平衡器或循环 DNS 或所有这些服务器前面的东西的答案。然而,他的句子“访问谷歌网页的客户端数量必须超过他们拥有的服务器数量”已经被你们都错误地称为“子套接字”的存在所回答。同样,这不是一个好问题,除非您报告不准确。

采访者:你觉得谷歌处理银行网站的方式有什么不同吗?

我:在 TCP-IP 套接字级别,应该是类似的。在请求级别,略有不同,因为维护了一个会话来保持银行网站中请求之间的状态。

你几乎做对了。存在与 Google 以及银行网站的 HTTP 会话。这不是什么大问题。他应该问的是事实,而不是你的意见。

总的来说,(a)你完全没有通过面试,(b)你沉迷于太多的猜测。你应该简单地说“我不知道”,然后让面试继续你知道的事情。

【讨论】:

好的。需要澄清 1)您提到“TCP 服务器每个接受的连接都有一个单独的套接字”,这是绝对正确的。但这仅适用于接受的连接。服务器套接字已打开以进行侦听。客户端第一次发出请求时,它需要创建一个新的 Socket 并将工作委托给该套接字。仅建立 TCP 连接。直到新的套接字创建尚未完成,主线程将被阻塞(但这将是非常非常小的仍然被阻塞)。这有意义吗? 还有一点很重要:对于使用 PC 浏览并在浏览器中打开三个具有不同 url 的选项卡的典型客户端,操作系统会使用 IP:port 对创建三个套接字。对于一个连接,就变成了四对 SRC-IP、SRC-PORT 和 DEST-IP,DEST-SRC 正确吗? @brainstorm TCP 服务器打开 1 个监听套接字;它循环调用accept() 来接收套接字,然后启动一个线程来处理它们,将它们输入到select() FD 集中,或者启动一些异步的东西。 accept() 正在阻塞,accept 循环是决定速率的步骤,但断言它阻塞其他客户端的说法太多了。由于积压队列,其他客户端可以继续连接。在接受循环开始接受它们之前,它们不会获得服务,但这应该足够快以至于难以察觉,除非服务器编程不当。 @brainstorm 您不能将浏览器选项卡与套接字等同起来。浏览器使用连接池,因此没有 1:1。而加载页面可能需要加载图片、.css/.js 文件等,这通常由多个套接字并行完成。

以上是关于Google 会为它收到的每个请求打开多少个套接字?的主要内容,如果未能解决你的问题,请参考以下文章

我一次可以打开多少个 TCP 套接字? [复制]

是为频繁请求保持一个套接字打开,还是每次都关闭套接字更好

一次可以处理多少个请求

“aspNetDisabled”类在哪里定义,为啥 ASP.NET 会为它呈现干扰性的重复 CSS“类”属性?

可能有多少个套接字连接?

使用 React、Redux 和 Websocket 处理请求