TCP-IP面试问题详解

为什么握手需要三次呢?两次可不可以?四次可不可以?

被问烂的问题之一,只需要解释下每次握手,双方都获得了哪些信息即可解答。

  1. 客户端发出SYN包,服务器收到了这个SYN包。此时客户端什么都不知道,而服务器由于收到了这个包,服务器可以知道,客户端的发送能力没有问题,且服务器自己的接收能力没问题。
  2. 服务器发送ACK+SYN包给客户端,客户端收到了。那么客户端此时就知道了自己发送能力(第一个包已经被服务器收到了)和接收能力没问题,与此同时服务器的发送能力和接收能力也没问题;到这一步客户端对于自己的能力和服务器的能力都有了了解了,但是,服务器此时还不能确认。
  3. 所以客户端会发送ACK的包给服务器,服务器收到之后,就可以知道自己的发送能力和接收能力没有问题,同时客户端的发送和接收能力也有没有问题。

所以,两次是不可以的,如果两次只有客户端知道自己和服务器的的发送、接收能力没有问题,但是服务器并不知道自己的发送能力和客户端的接收能力。四次从理论上来说完全OK,但是我明明三次能解决,为什么需要四次呢?

为什么挥手需要四次?

被问烂的问题之二。双方都可以主动提出断开连接,下面以客户端主动向服务器要求断开连接为例子。

  1. 客户端发送FIN包给服务器。
  2. 服务器确认该包,发送ACK给客户端,代表自己知晓。由于这是客户端主动提起的,所以客户端必然不会再发数据给服务器了,但是!服务器还是有可能有数据要发送给客户端。
  3. 当服务器也没有数据要发送给客户端了,那么就会发送FIN包给客户端.
  4. 最后客户端发送ACK给服务器,代表自己已经知晓,挥手结束。

那么为什么会比握手多一次呢?仔细观察下就可以发现,其实挥手的第二次和第三次就是握手的第二次,握手由于没有数据要发送,可以把这两次合二为一。

解析从浏览器地址栏敲入www.xxxx.com的一次全过程

这个问题我个人觉得比上面两个好太多了。但是严格意义来讲,这个比较倾向于前端吧23333333

  1. 首先,当你按下回车,第一步就是把域名转换成ip地址,但是这个步骤也是一层又一层的:
    1. 浏览器会先去查下自己的缓存里有没有这个对应关系,有的话直接就帮你返回,没有的话继续找。
    2. 继续在系统预设的host文件中查找。
    3. 通过DNS系统查找了。
  2. OK现在你已经能够得知你这个域名对应的ip地址了,接下来就是拜托OS去和该ip地址的服务器进行TCP连接了,即进行三次握手。
  3. 接下来就需要准备HTTP的报文了,那么浏览器会为你构建好请求头、请求体和请求内容,并发送给服务器。服务器收到之后会进行响应(进行响应的内容即为后端需要处理的事务了),响应内容一般都是html、css等,这些内容需要由浏览器来进行渲染,最后变成呈现在你眼前的内容。

HTTP和HTTPS的区别

HTTP是明文传输的,我们都知道。这样显然有被窃听的风险,所以我们需要浏览器和服务器之间协商出一个密钥,用这个密钥来加密解密就可以了。

这里存在一个问题,我是怎么知道对方是谁的呢?这里其实有一个原则:信任必须要有一个基点,必须从这个基点开始出发,推出一条信任链。这个就跟你无法辨别出现在的世界到底是真实的,还是我们其实都是一台超级计算机控制着,它为我们的大脑来模拟所有的世界上的一切。所以人们在计算机里存放了一些证书,这些证书你必须无条件信任它们,然后通过它们,就可以推测出一条长长的信任链,这样就能辨别你要访问的目标服务器了。也就可以通过数字签名、公私钥加密来完成密钥的交换,也就可以用那个密钥来进行数据的传输而不被窃听了。

Localhost和127之间的区别

首先引用一下TCP/IP详解卷一里面的一段话:

根据惯例,大多数系统把IP地址127.0.0.1分配给这个接口,并命名为localhost。

上面的这个接口,指的是环回接口。下面这张图真的非常非常重要,理解它可以极大提升你对环回接口的理解。

image-20200425143108489

接下来再引一段话:

一旦传输层检测到目的端地址是环回地址时,应该可以省略部分传输层和所有网络层的逻辑操作。但是大多数的产品还是照样完成传输层和网络层的所有过程。只是当IP数据报离开网络层时把它自己返回给自己。

也就是说,大部分产品,如果是环回地址,那么数据从应用层-传输层下来,只是传送到IP层,然后又回到IP层并且继续往传输层往上走。

然后我又去查了wiki:

任何发往环回地址的数据包,其处理都在 TCP/IP 协议叠的链路层中实现的。这些数据包不会交由网卡(NIC)或者设备驱动程序处理,既不应在电脑系统以外出现,也不可经路由器转发。如此一来,电脑上即使没有实体网卡,也可进行软件测试或者运行本机服务。

我自己做的实验,用wireshark抓包,发现数据报是应该会传送到数据链路层,然后会给数据报头部加上一个Null loopback的头部,数值是02 00 00 00,这点在官网上可以查到。所以应该是wiki上面的更加准确。

根据这点,我们又知道网卡是工作在数据链路层的Mac子层和物理层。所以理论上,如果你的电脑在物理上,把网卡给拔掉,那么你ping任何人都不会通(废话),但是你还是可以ping通127和localhost。

接下来是我做的一些实验:

Windows 7上,我直接在网络共享中心禁用掉网卡,发现不论是ping 127还是Localhost,都可以ping通,嗯,确实符合之前说的。但是这真的正确吗?先来看看linux的表现。

在Ubuntu 16.04 上,ifconfig lo down,无论是ping 127还是localhost都无法通。哎?这是不是就不对了呢?为什么Windows上面可以而linux上面不行呢?

这个链接有详细的解答。大意就是历史的原因造成了windows用的是NetBIOS这个协议栈,而不是TCP/IP。所以导致了上面结果的发生。

而在linux上面,这个调用是这个样子的:调用ping命令 -> 使用socket系统调用 -> 路由 -> 找到lo内核网络驱动 -> 驱动连不上(因为我们down掉了),所以会ping不通。

然后是mysql这个软件,对于localhost和127确实是不同对待的,127用的是tcp/ip,而对于Localhost用的是unix domain socket,可能会发生鉴权的问题:

1
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)

最后的最后,扯了一大堆之后,localhost就是127这个ip地址的域名而已;只是由此引申出了不少问题,而且极少数的软件(mysql)会针对host进行单独的配置。

socket之间的区别

我们平时说的,是在TCP/IP协议中用到的socket,或者说,叫Network socket更为贴切。虽然这种socket在网络上得到了广泛的发展,而且理论上在同一机器内进程之间的通信也完全可用(地址写127.0.0.1即可),但是在本机上为了效率,我们会采用Unix domain socket——你可能不认识它,但是它还有另外一个名字,IPC(inter-process communication)。

所以它们之间最最主要的区别就是:

  • Network socket需要走TCP/IP协议栈
  • IPC则不需要经过网络协议栈,不需要打包拆包、计算校验和、维护序号和应答等,只是将应用层数据从一个进程拷贝到另一个进程。当然速度贼快啦。