面试总结
1.TCP建立连接(三次握手)
建立一个 TCP 连接时,需要三次握手,即需要客户端和服务器总共发送3个包。三次握手的目的是连接服务器指定端口,建立 TCP 连接,并同步连接双方的***和确认号,交换 TCP 窗口大小信息。在 socket 编程中,客户端执行 connect() 时。将触发三次握手。
TCP服务器进程先创建传输控制块TCB,时刻准备接受客户进程的连接请求,此时服务器就进入了LISTEN(监听)状态;
第一次握手(SYN=1, seq=x):
客户端发送一个 TCP 的 SYN (同步位)为1的包,指明客户端打算连接的服务器的端口,以及初始序号 x,保存在包头的***(Sequence Number)字段里。
发送完毕后,客户端进入 SYN-SENT(同步已发送)状态。
第二次握手(SYN=1, ACK=1, seq=y, ACKnum=x+1):
服务器发回确认包(ACK)应答。即 SYN 标志位和 ACK 标志位均为1。服务器端选择自己 ISN ***,放到 Seq 域里,同时将确认序号(Acknowledgement Number)设置为客户的 ISN 加1,即x+1。
发送完毕后,服务器端进入 SYN_RCVD (同步收到)状态。
第三次握手(ACK=1,seq=x+1,ACKnum=y+1):
客户端再次发送确认包(ACK),SYN 标志位为0,ACK 标志位为1,并且把服务器发来 ACK 的序号字段+1,放在确定字段中发送给对方,并且在数据段放写ISN的+1
发送完毕后,客户端进入 ESTABLISHED (已建立连接)状态,当服务器端接收到这个包时,也进入 ESTABLISHED 状态,TCP 握手结束。
2.为什么需要三次握手而不是两次
主要防止已经失效的连接请求报文突然又传送到了服务器,从而产生错误。
如果使用的是两次握手建立连接,假设有这样一种场景,客户端发送了第一个请求连接并且没有丢失,只是因为在网络结点中滞留的时间太长了,由于TCP的客户端迟迟没有收到确认报文,以为服务器没有收到,此时重新向服务器发送这条报文,此后客户端和服务器经过两次握手完成连接,传输数据,然后关闭连接。此时此前滞留的那一次请求连接,网络通畅了到达了服务器,这个报文本该是失效的,但是,两次握手的机制将会让客户端和服务器再次建立连接,由于现在客户端并没有发出建立连接的请求,因此不会理睬服务器的确认,也不会向服务器发送数,而服务器以为新的运输连接已经建立了,并一直等待客户端发来数据。服务器的许多资源就这样这将导致不必要的错误和资源的浪费。
如果采用的是三次握手,就算是那一次失效的报文传送过来了,服务端接受到了那条失效报文并且回复了确认报文,但是客户端不会再次发出确认。由于服务器收不到确认,就知道客户端并没有请求连接。
3.TCP四次挥手
数据传输完毕后,双方都可释放连接。最开始的时候,客户端和服务器都是处于ESTABLISHED状态,然后客户端主动关闭,服务器被动关闭。
第一次挥手(FIN=1,seq=u)
假设客户端想要关闭连接,客户端发送一个 FIN 标志位置为1的包,表示自己已经没有数据可以发送了,但是仍然可以接受数据。
发送完毕后,客户端进入 FIN_WAIT_1 (终止等待1)状态。
第二次挥手(ACK=1,seq=v,ACKnum=u+1)
服务器端确认客户端的 FIN 包,发送一个确认包,表明自己接受到了客户端关闭连接的请求,但还没有准备好关闭连接。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。
发送完毕后,服务器端进入 CLOSE_WAIT(关闭等待) 状态,客户端接收到这个确认包之后,进入 FIN_WAIT_2 (终止等待2)状态,等待服务器端关闭连接。
第三次挥手(FIN=1,ACK=1,seq=w,ACKnum=u+1)
服务器端准备好关闭连接时,向客户端发送结束连接请求,FIN 置为1。
发送完毕后,服务器端进入 LAST_ACK (最后确认)状态,等待来自客户端的最后一个ACK。
第四次挥手(ACK=1,seq = u+1,ACKnum=w+1)
客户端接收到来自服务器端的关闭请求,发送一个确认包,并进入 TIME_WAIT(时间等待)状态,等待可能出现的要求重传的 ACK 包。
服务器端接收到这个确认包之后,关闭连接,进入 CLOSED 状态。
客户端等待了某个固定时间(两个最大段生命周期,2MSL,2 Maximum Segment Lifetime)之后,没有收到服务器端的 ACK ,认为服务器端已经正常关闭连接,于是自己也关闭连接,进入 CLOSED 状态。
4.为什么客户端最后还要等待2MSL?
第一,保证客户端发送的最后一个ACK报文能够到达服务器,因为这个ACK报文可能丢失,站在服务器的角度看来,我已经发送了FIN+ACK报文请求断开了,客户端还没有给我回应,应该是我发送的请求断开报文它没有收到,于是服务器又会重新发送一次,而客户端就能在这个2MSL时间段内收到这个重传的报文,接着给出回应报文,并且会重启2MSL计时器。
第二,防止类似与“三次握手”中提到了的“已经失效的连接请求报文段”出现在本连接中。客户端发送完最后一个确认报文后,在这个2MSL时间中,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。这样新的连接中不会出现旧连接的请求报文。
5.为什么建立连接是三次握手,关闭连接确是四次挥手呢?
建立连接的时候, 服务器在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。
而关闭连接时,服务器收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,己方是否现在关闭发送数据通道,需要上层应用来决定,因此,己方ACK和FIN一般都会分开发送。
6.Linux中挂载函数
查询和自动挂载
mount:查询系统中已经挂载的设备
mount -a:依据配置文件 /etc/fstab 的内容,自动挂载。/etc/fstab 配置文件就是配置自动自动挂载分区的。如果你在这个配置文件里配置了开机自动挂载光盘、U盘等外部设备的分区,也可以,但假如开机时没有检测到这个外部设备(这是正常的,比如忘记把光盘放到光驱……)就可能导致系统开机时的崩溃
挂载命令的格式
mount [-t 文件系统] [-o 特殊选项] 设备文件名 挂载点
-t 文件系统:加入文件系统类型来指定挂载的类型,可以是 ext3、ext4、iso9660等文件系统
-o 特殊选项:可以指定挂载的额外选项
挂载点:是以已经存在的空白目录作为挂载点的
可参考:
https://www.runoob.com/linux/linux-comm-mount.html
7.Linux中查看端口号
1.使用lsof
lsof -i:端口号查看某个端口是否被占用
2.使用netstat -anp | grep 8080
-a :all,表示列出所有的连接,服务监听,Socket资料
-t :tcp,列出tcp协议的服务
-u :udp,列出udp协议的服务
-n :port number, 用端口号来显示
-l :listening,列出当前监听服务
-p :program,列出服务程序的PID