计算机网络面试核心大总结

本文详细介绍了计算机网络面试中的核心知识点,包括OSI七层模型与TCP/IP四层结构的关系,TCP的三次握手与四次挥手过程,TCP与UDP的区别,TCP滑动窗口的原理,HTTP的主要特点和状态码,以及HTTPS与SSL的安全机制。同时,还讨论了TCP的保活机制和服务器处理大量CLOSE_WAIT状态的原因,以及Socket通信的基本流程。
摘要由CSDN通过智能技术生成

 

1 网络基础知识

1.1 OSI七层参考模型

全称:开放系统互连参考模型(Open System Interconnection Reference Model,OSI/RM)

补充:为什么要有一个个层:

物理层:010101比特流,设备之间原始数据的传输,数模转换(发送端)和模数转换(接收端)

-》传输过程可能出现错码和误码?-------又问题,引入下一层:数据链路层

 

数据链路层:将原始比特流转换成逻辑传输符号,提供纠错编码,格式变为帧

-》出现多个网络节点,应该选择哪个节点?

 

网络层:通过路由选择,选择最佳路径,数据格式是IP数据包

-》某次连接传输的数据可能很大,会出现错传、漏传

 

传输层:将数据拆分成段,提供维护连接的机制(流量控制、拥塞控制)

-》对用户来说每次都要使用传输层拆分,再使用网络层寻路很麻烦

 

会话层:提供建立连接和维护连接的机制,方便用户使用

-》不同操作系统之间的网络传输如何互通?linux/windows

 

表示层:提供编码转换、加解密、解压缩

-》接收方不知道发送发发送的是什么东西、数据有多长?

 

应用层:规定发送方和接收方必须使用固定长度的消息头,并且消息头固定格式,并标明长度等信息。

1.物理层

设备之间原始数据的传输数据格式:比特流。

2.数据链路层

原始比特流转换成逻辑传输数据,建立相邻结点之间的数据链路,mac地址寻址,数据格式:帧

3.网络层

将数据链路层提供的帧组成数据包,通过路由算法提供最佳传输路径数据格式:IP数据包

数据链路层解决同一网络节点间的传输,网络层解决不同子网间的传输。(IP是网络层)

4.传输层

数据格式:也称作数据包(packets)(TCP的数据单元称为段(segments)UDP的数据单元称为数据报(datagrams))

拆分数据包,提供端对端不同主机用户进程数据传输,提供可靠或不可靠传输及流量控制,是连接通信子网和资源子网的桥梁。

5.会话层

不参与具体的传输,提供建立和维护应用间通信的机制。

6.表示层

数据的表示方式(格式处理及编码转换)和特定功能(加解密,解压缩)的实现

7.应用层

为用户提供服务,为操作系统或者应用程序提供访问网络的的接口

应用层协议的代表包括:Telnet、FTP、HTTP、SNMP等

 

1.2 TCP/IP四层结构

1.链路层:

包括物理层和数据链路层,是通过MAC地址传输数据的

2.网络层:

包括多种协议

IP协议:通过路由选择将数据封装后交给链路层

ICMP协议(Internet Control Message Protocol):用于主机和路由器直接传递控制消息,常用的ping就是用这个协议。

ARP协议(Address Resolution Protocol):是正向地址解析协议,通过IP查找mac地址。

RARP协议:是反向地址解析协议,通过mac地址查找IP。

3.传输层

 TCP协议:传输控制协议,是面向连接的、可靠的、基于IP的传输层协议

UDP协议:用户数据报协议,提供面向事物的、简单、不可靠的信息传输协议

4.应用层

FTP协议:文件传输协议,用于文件的上传下载。

Telnet协议:用户远程登录服务。

DNS(Domain Name System)协议:域名解析协议,提供域名到IP的解析。

SMTP(Simple Mail Transfer Protocol)协议:简单的邮件传送协议,用于控制信件的发送中转。

NFS协议:网络文件系统,用于不同主机间文件共享。

HTTP协议:超文本传输协议,用于实现互联网访问功能。

 

1.3 OSI七层协议和TCP/IP协议之间的关系

                       链路层                           物理层
                        数据链路层
                       网络层                           网络层
                       传输层                           传输层
                       应用层                           会话层
                           表示层
                           应用层

  • OSI更注重通信模块必要的功能是什么
  • TCP/IP更注重实现协议应该开发哪种程序

2. TCP的三次握手和四次挥手

2.1 TCP报文头结构定义

其中:

seq是32位序号,ack是32位确认序号

  • URG:紧急指针标志
  • ACK:确认序号标志
  • PSH:push标志
  • RST:重置连接标志
  • SYN:同步序号,用于建立连接过程
  • FIN:finsh标志,用于释放连接

2.2 TCP三次握手

初始时,服务器端处于LISTEN监听状态

第一次握手:客户端发送SYN包到服务器(SYN标志位为1,seq=x)并进入SYN-SENT状态,等待服务器确认;

第二次握手:服务端确认客户端的SYN包(ACK标志位为1,ack=x+1),同时自己也发送一个SYN包(SYN标志位为1,seq=y),并且进入到SYN-RCVD状态;

第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送一个确认包(ACK标志位为1,ack=y+1),此包发送完毕,客户端和服务器端进入ESTABLISHED状态,完成三次握手。

为什么需要三次握手才能建立起链接

为了初始化Sequence Number的初始值

 首次握手的隐患--SYN超时

可能出现的问题及解决方案:

问题起因 :

  1. Server收到Client的SYN,回复SYN+ACK的时候未收到ACK确认
  2. 则Server不断重试直至超时,Linux默认等待63秒(1+2+4+8+16+32)才断开连接。

 

SYN超时可能会带来恶意代码攻击,应对SYN Flood的防护措施是:

  1. SYN队列满后,通过tcp_syncookies参数回发SYN Cookie
  2. 若为正常连接则Client会回发SYN Cookie,直接建立连接。

建立连接后,Client出现故障怎么办?

保活机制:

  1. 向对方发送保活探测报文,如果未收到响应则继续发送,
  2. 尝试次数达到保活探测次数仍未收到响应则中断连接

2.3 TCP的四次挥手

第一次挥手:客户端发送一个FIN包(FIN=1,seq=u),用来关闭客户端到服务端的数据传送,之后客户端进入FIN_WAIT-1状态;

第二次挥手:服务端接收到FIN后,发送一个ACK给客户端,确认序号ack为收到序号seq+1(与SYN相同,一个FIN占用一个序号),服务端进入到CLOSED_WAIT状态,客户端进入到FIN-WAIT-2状态;

第三次挥手:服务端发送一个FIN,用来关闭服务端到客户端的数据传送,并且服务端进入LAST_ACK状态;

第四次挥手:客户端收到FIN后,客户端进入TIME_WAIT状态,接着发送一个ACK给服务端,确认序号ack为收到序号seq+1.紧接着服务器端进入CLOSED状态,完成四次挥手

 

为什么会有TIME_WAIT状态?

1.确保有足够的时间让对方收到ACK包

2.避免新旧混淆

(  假设最终的ACK丢失,服务端将重发FIN,客户端必须维护TCP状态信息以便可以重发最终的ACK,否则会发送RST,结果主机认为发生错误。TCP实现必须可靠地终止连接的两个方向(全双工关闭),客户端必须进入 TIME_WAIT 状态,因为客户端可能面临重发最终ACK的情形。)

注:TIME_WAIT: 

表示收到了对方的FIN报文,并发送出了ACK报文,就等2MSL后即可回到CLOSED可用状态了。如果FIN WAIT1状态下,收到了对方同时带FIN标志和ACK标志的报文时,可以直接进入到TIME_WAIT状态,而无须经过FIN_WAIT_2状态。(主动方)

为什么需要四次挥手才能断开连接

因为全双工,发送方和接收方都需要FIN报文和ACK报文

服务器出现大量CLOSE_WAIT状态的原因 

 对方关闭socket连接,我方忙于读或写,没有及时关闭连接

  • 检查代码,特别是释放资源的代码
  • 检查配置,特别是处理请求的线程配置

 

3 UDP

3.1 UDP报文头结构

英文:

中文:

概括:

  1.  由16位源端口号
  2. 16位目的端口号
  3. 16位UDP长度
  4. 16为UDP检验和
  5. 以及 数据 组成。

3.2 UDP特点:

1. 面向非连接的

2.不维护连接状态,支持同时向多个客户端传输相同的消息

3.数据包报头只有8个字节,额外开销比较小

4.吞吐量只受限于生成速率、传输速率以及及其性能

5.尽最大努力交付,不保证可靠交付,不需要维持复杂的链接状态表

6.面向报文,不对应用程序提交的报文信息进行拆分或者合并

关键词:非连接、多发、报头小、吞吐量、最大努力交付、面向报文

 

3.3 TCP和UDP的区别

1.面向连接VS非连接

2.可靠性

3.有序性

4.量级

5.速度 

4 TCP的滑动窗口

4.1 基本概念:

4.1.1 RTT和RTO:

RTT:(Round Trip Time)发送一个数据包收到对应的ACK,所花费的时间

RTO:(Retransmission TimeOut)重传时间间隔

 

4.2 TCP使用滑动窗口做流量控制与乱序重排的目的

  1. 保证TCP的可靠性
  2. 保证TCP的流控特性

->TCP报文头中的Window即指滑动窗口

 

4.3 滑动窗口数据的计算:

以下均为从左到右序号逐渐递增

发送端:
LastByteAcked:已经发送并且收到回复的最后一个序号位置
LastByteSent:已经发送但还没有时候到回复的最后一个序号位置
LastByteWritter:已经准备好的但还没发送的最后一个序号位置

接收端:
LastByteRead:收到并已经回复的最后一个位置
NextByteExcepted:收到的连续最大的sequence的位置(已经收到但还没有发送回复ACK)
LastByteRcvd:已收到的最后一个字节的位置

计算:
AdvertisedWindow = MaxRcvBuffer - (LastByteRcvd - LastByteRead)
EffectiveWindow = AdvertisedWindow - (LastByteSendt - LastByteAcked)

其中:AdvertisedWindow(接收方还可以处理的量)、MaxRcvBuffer(接收方能接收的最大数据量)、
EffectiveWindow(窗口内剩余可发送数据大小)

 

4.4 滑动窗口的基本原理

4.4.1 TCP发送方:

 

包含四个状态:发送并收到回复、发送还没收到回复、还没发送但是可发送、还没发送并且不可发送

(1)假设起始状态:[32~45][46~51]共同构成了滑动窗口,其中前一部分是已发送的还没收到确认的,后一部分是可发送还没发的。


(2)假设发送的片段[32~36],发送端收到接收端的ACK回复,那么滑动窗口即可向右移动5个字节
(3)此时可以将[46~51]发送出去,并且[52~56]由不可发送变为可发送,整个滑动窗口向右移动了5个字节的位置

4.4.2 TCP接收方:

包含三个状态:收到并且已回复、还没收到并且允许发送、还没收到也不允许发送

注:

1. 由于ACK直接由TCP栈回复,默认没有应用延迟,不存在已接收但未回复的状态

2.未接收但是可以接收的这段空间称为接收窗口

3。应用会根据自身处理能力的变化,通过本端TCP接收窗口大小的控制来实现对端的发送窗口进行流量限制

 

5 HTTP

HTTP:Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW:World Wide Web )服务器传输超文本到本地浏览器的传送协议;HTTP是基于TCP/IP通信协议来传递数据的。

5.1 主要特点:

HTTP是应用层协议

1.支持服务端/客户端两种模式
2.简单快速:
客户向服务器请求服务时,只需传送请求方法和路径。请求的方法常用的有GET、HEAD、POST。每种方法规定了客户与服务器联系的类型不同。由于HTTP协议简单,使得HTTP服务器的服务规模小,因而通信速度很快。
3.灵活
允许传输任意类型的数据对象。
4.无连接
限制每次连接只处理一个请求
5.无状态
对事物处理没有记忆能力

5.2 报文结构

å¨è¿éæå¥å¾çæè¿°

                             å¨è¿éæå¥å¾çæè¿°

5.3 请求响应的步骤

1.客户端连接到服务端
2.发送HTTP请求
3.服务器接收请求并返回HTTP响应
4.释放TCP连接
5.客户端浏览器解析HTTP内容


在浏览器地址栏中键入URL,按下回车之后经历的流程:

1.DNS解析
2.TCP连接
3.客户端发送HTTP请求
4.服务端接收HTTP请求并返回HTTP报文
5.浏览器解析渲染页面
6.连接结束

5.4 HTTP状态码:

5.4.1 五种可能的取值:

1XX:指示信息,表示已经收到请求,继续处理
2XX:成功--表示请求已经被成功接收、理解、接受
3XX:重定向--要完成请求必须进行进一步操作
4XX:客户端错误--请求有语法错误或者无法实现
5XX:服务端错误--服务器未能实现合法的请求

5.4.2 常见的状态码:

200 OK:正常返回信息
400 Bad Request : 客户端请求有语法错误,不能被服务器所理解
401 Unauthorized : 请求未经授权(这个状态代码必须和WW-Authenticate报头域一起使用)
403 Forbidden : 服务器收到请求,但是拒绝提供服务
404 Not Found : 请求资源不存在,eg,输入了错误的URL
500 Internal Server Error : 服务器发生不可预期的错误
503 Server Unavaliable : 服务器当前不能处理客户端的请求

5.5 Get请求和POST请求的区别

三个层面:

  1. HTTP报文层面:GET将请求放在URL,POST放在报文体中
  2. 数据库层面:GET符合幂等性和安全性,POST不符合
  3. 其他层面:GET可以被缓存、被存储,POST不行

注:HTTP 幂等方法,是指无论调用多少次都不会有不同结果的 HTTP 方法。不管你调用一次,还是调用一百次,一千次,结果都是相同的。

5.6 Cookie和Session的区别

1.Cookie是什么?

(1)是由服务器发给客户端的特殊信息,以文本的形式存放在客户端

(2)客户端再次请求的时候,会把Cookie回发

(3)服务器接收到后,会解析Cookie生成与客户端相对应的内容

Cookie的发送过程如图:

2.Session是什么?

(1)服务器端的机制,在服务器上保存的信息

(2)解析客户端请求并操作session id,按需保存状态信息

Session的实现方式
(1)使用Cookie来实现

(2)使用URL回写来实现

Cookie和Seesion的区别

(1)Cookie数据存放在客户的浏览器上,Session数据存放在服务器上

(2)Session相对于Cookie更安全

(3)若考虑减轻服务器负担,应该使用Cookie

 

6 HTTP和HTTPS

6.1 简介

HTTP:Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW:World Wide Web )服务器传输超文本到本地浏览器的传送协议;HTTP是基于TCP/IP通信协议来传递数据的。

HTTPS:是以安全为目标的HTTP通道,简单讲是HTTP的安全版,即HTTP下加入SSL层,你也可以说:HTTPS = HTTP + SSL

6.2  HTTP和HTTPS的区别:

1.HTTP默认端口为80,HTTPS默认端口为43;

2.HTTP不安全,HTTPS安全;(HTTPS=HTTP+加密+认证+完整性保护)

3.HTTP明文传输,HTTPS密文传输;

4.HTTP无需证书,HTTPS需要CA申请证书

5.HTTP的URL以http://开头,HTTPS的URL以https://开头

6.在OSI网络模型中,HTTP工作与应用层,而HTTPS工作在传输层 

7. HTTPS = HTTP + 加密 + 认证 + 完整性保护,比HTTP安全

6.3 SSL是什么?

SSL(Security Sockets Layer)

1.为网络通信提供安全及数据完整性的一种安全协议

2.是操作系统对外的API,SSL3.0后更名为TLS

3.采用身份验证和数据加密保证网络通信的安全和数据的完整性

加密的方式 

  1. 对称加密:加密和解密都使用同一个密钥
  2. 非对称加密:加密使用的密钥和解密使用的密钥是不相同的
  3. 哈希算法:将任意长度的信息转换为固定长度的值,算法不可逆
  4. 数字签名:证明某个消息或者文件是某人发出/认同的

6.4 HTTPS数据传输流程

 1.浏览器将支持的加密算法信息发送给服务器

2.服务器选择一套浏览器支持的加密算法,以证书的形式回发浏览器

3.浏览器验证证书合法性,并结合证书公钥加密信息发送给浏览器

4.服务器使用私钥解密信息,验证哈希,加密响应消息回发浏览器

5.浏览器解密响应消息,并对消息进行验证,之后进行加密交互数据

6.5 HTTPS真的安全吗?

 1.浏览器默认填充http://,请求需要进行跳转,有被劫持的风险

2.可以使用HSTS(HTTP Strict Transport Security)优化

 

 

7 Socket

7.1 简介

Socket(套接字)是TCP/IP协议的抽象,是操作系统对外开放的接口

7.2 Socket通信流程

server端

  • 1.socket() 创建socket
  • 2.bind() 绑定socket和端口号
  • 3.listen() 监听该端口号
  • 4.accept() 接收来自客户端的连接请求
  • 5.recd() 从socket中读取字符
  • 6.close() 关闭socket

client端

  • 1.socket() 创建socket
  • 2.connect() 连接指定计算机的端口
  • 3.send() 向socket中写入指定信息
  • 4.close() 关闭socket

 

7.3 常见面试题:

1.编写一个简易的web server,有客户端与服务器端,客户向服务器发送一个字符串,服务器收到该字符串后将其打印到命令行上,然后向客户端返回该字符串的长度,最后,客户端输出服务端返回的该字符串的长度,分别用TCP和UDP两种方式去实现。

TCP实现如下

(1)服务器端:TCPServer

package IMUHERO;
 
import java.net.ServerSocket;
import java.net.Socket;
 
public class TCPServer {
    public static void main(String[] args) throws Exception {
        //创建socket,并将socket绑定到65000端口
        ServerSocket ss = new ServerSocket(65000);
        //死循环,使得socket一直等待并处理客户端发送过来的请求
        while (true) {
            //监听65000端口,直到客户端返回连接信息后才返回
            Socket socket = ss.accept();//侦听并接受到此套接字的连接
            //获取客户端的请求信息后,执行相关业务逻辑
            new LengthCalculator(socket).start();
        }
 
        
    }
}

(2) 客户端:TCPClient

package IMUHERO;
 
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
 
public class TCPClient {
    public static void main(String[] args) throws Exception {
        //创建socket,并指定连接的是本机的端口号为65000的服务器socket
        Socket socket = new Socket("127.0.0.1", 65000);
        //获取输出流
        OutputStream os = socket.getOutputStream();
        //获取输入流
        InputStream is = socket.getInputStream();
        //将要传递给server的字符串参数转换成byte数组,并将数组写入到输出流中
        os.write(new String("hello world").getBytes());
        int ch = 0;
        byte[] buff = new byte[1024];
        //buff主要用来读取输入的内容,存成byte数组,ch主要用来获取读取数组的长度
        ch = is.read(buff);
 
        /**
         * API详解:read(byte[] b) :
         * 从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。以整数形式返回实际读取的字节数
         **/
 
        //将接收流的byte数组转换成字符串,这里是从服务端回发回来的字符串参数的长度
        String content = new String(buff, 0, ch);
        
        /**
         * API详解:String shuzu=new String(byt, 0, len);
         * new String(bytes, offset, length)
         * bytes为要解译的字符串;
         * offset为要解译的第一个索引,比如从0开始就是从字符串bytes的第一个字符开始;
         * length为要解译的字符串bytes的长度
         * **/
 
        System.out.println(content);
        //不要忘记关闭输入输出流以及socket
        is.close();
        os.close();
        socket.close();
 
    }
}

 

(3)辅助函数:

 

package IMUHERO;
 
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
 
public class LengthCalculator extends Thread {
    //以socket为成员变量
    private Socket socket;
 
    public LengthCalculator(Socket socket) {
        this.socket = socket;
    }
 
    @Override
    public void run() {
        try {
            //获取socket的输出流
            OutputStream os = socket.getOutputStream();
            //获取socket的输入流
            InputStream is = socket.getInputStream();
            int ch = 0;
            byte[] buff = new byte[1024];
            //buff主要用来读取输入的内容,存成byte数组,ch主要用来获取读取数组的长度
            ch = is.read(buff);//API文档见客户端代码
            //将接收流的byte数组转换成字符串,这里获取的内容是客户端发送过来的字符串参数
            String content = new String(buff, 0, ch);//API文档见客户端代码
            System.out.println(content);
            //往输出流里写入获得的字符串的长度,回发给客户端
            os.write(String.valueOf(content.length()).getBytes());
            //不要忘记关闭输入输出流以及socket
            is.close();
            os.close();
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

先运行server端进行监听,然后运行client端发送数据,执行结果如下:


UDP实现如下:

服务器端:UDPServe

package IMUHERO;
 
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
 
public class UDPServer {
    public static void main(String[] args) throws Exception {
        DatagramSocket socket = new DatagramSocket( 65001);
 
        //初始化一个空的数据报,并接收输入流
        byte[] buff = new byte[100];
        DatagramPacket receivePacket = new DatagramPacket(buff,buff.length);
        socket.receive(receivePacket);
 
        //解析数据
        byte[]data=receivePacket.getData();
        String content = new String(data,0,receivePacket.getLength());
        System.out.println(content);//打印解析的字符串
 
        //发送数据
        byte[] sendContent = String.valueOf(content.length()).getBytes();
        InetAddress address = receivePacket.getAddress();
        int port = receivePacket.getPort();
        DatagramPacket sendPacket = new DatagramPacket(sendContent,sendContent.length,address,port);
        socket.send(sendPacket);
    }
 
}

客户端:UDPClient:

package IMUHERO;
 
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
 
public class UDPClient {
    public static void main(String[] args) throws Exception {
        //初始化socket
        DatagramSocket socket = new DatagramSocket();
        //初始化数据
        byte [] buff = "Hello world".getBytes();
 
        //发送数据
        //将ip地址封装成InetAddress对象
        InetAddress address = InetAddress.getByName("127.0.0.1");
        int port = 65001;
        DatagramPacket sendPacket = new DatagramPacket(buff,buff.length,address,port);
        socket.send(sendPacket);
 
        //接收数据
        byte[]data=new byte[100];
        //封装成一个数据报
        DatagramPacket recevicePacket = new DatagramPacket(data,data.length);
        socket.receive(recevicePacket);
 
        byte[]receiveData = recevicePacket.getData();
        String content = new String(receiveData,0,receiveData.length);
        System.out.println(content);
 
    }
}

结果

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值