计算机网络

本文深入介绍了计算机网络的基础知识,包括OSI七层模型和TCP/IP四层协议族。重点讲解了TCP的三次握手和四次挥手过程,以及TCP与UDP的区别。同时,对HTTP协议进行了阐述,包括其主要特点、请求/响应流程、状态码和与HTTPS的区别。此外,还提及了Socket通信的基本概念及其在TCP和UDP中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

网络基础知识

OSI7层协议模型

  • 物理层 : 两台机器之间的bit流传输,负责将0101…的原始比特流转换为对应的高低电信号,数模转换与模数转换。单位是bit,设备有网卡网线
  • 数据链路层: 在比特流传输的过程中,可能存在错传、数据不完整等情况,数据链路层定义了如何格式化数据,以及对物理介质的访问。通常还提供错误检测和纠正,以提高数据传输的可靠性。单位是帧,设备有交换机。
  • 网络层: 将网络地址翻译成物理地址,决定数据路由路径。通过综合考虑发送优先权、网络拥塞程度、服务质量、可选路由的花费,来决定从一个网络节点A到另一个网络节点B的最佳路径。单位是数据包,设备有路由器,协议有IP。
  • 传输层: 解决了网络间的数据传输问题,对大文件切割成段落(segment),指定序号方便接收端按正确的顺序重组数据。单位是数据片segment,协议有TCP、UDP。
  • 会话层: 自动收发包、自动寻址,建立和管理应用程序之间的通讯。
  • 表示层: 信息的语法语义解析,加密解密,压缩解压。
  • 应用层: 规定了收发信息的请求/响应头、请求/响应体,协议有HTTP

OSI模型并没有提供具体的实现,只是一个具有指导意义的用于构建网络框架的参考模型。OSI的事实标准是TCP/IP4层协议。

TCP/IP 协议族

  • 应用层: 对应[应用层、表示层、会话层] head -> HTTP数据
  • 传输层:对应[传输层] head -> TCP首部 -> HTTP数据
  • 网络层:对应[网络层] head -> IP首部 -> TCP首部 -> HTTP数据
  • 链路层:对应[数据链路层、物理层] head -> 以太网首部 -> IP首部 -> TCP首部 -> HTTP数据

TCP

TCP ( transfer control protocol ) 简介

由于基于IP协议的网络层为了确保不独占通信线路,所以被设计成无状态、无连接的不安全的通信。仅讲上层传递的数据切分成更小的数据单元,通过路由发送到对端,不做收发顺序和数据完整性校验。

TCP是一种面向连接的、可靠的、基于字节流的传输层通信协议。将应用层的数据流分割成报文段发送给目标节点的TCP层。 通过给每个报文段一个序号(sequence number)保证接收端按序处理,同时通过ACK确认送达,如果在RTT超时时间内未收到确认,则默认为丢失,重传。TCP在收发端通过奇偶校验和来验证数据完整性。

TCP 报文格式

在这里插入图片描述

  • 源端口(source port)

  • **目标端口(destination port) **: ip地址在网络层标识,通过ip和端口唯一标示两个通信的进程(也叫socket套接字)

  • 序号(sequence number) : tcp传输的每个字节都按顺序编号,每个报文的序号 = 上一个报文的序号 + 上一个报文的数据长度

  • **确认号(acknowledgement number) **: 是期望收到对端下一个报文的第一个数据字节序号。例 B收到A的报文的序号是101,数据长度时200,则回复的确认号就是501。

  • 偏移(offset) : 标明数据和起始处的距离

  • 保留域(reserve): 保留域 默认置0

  • 控制位(TCP flags) :

    — URG :紧急指针标志

    ACK :确认序号标志

    — PSH :push标志 指明接收端接收数据后应直接交由应用程序 而不是进入缓冲队列

    — RST :重置连接标志 由于主机崩溃或其他原因出现错误的连接,或 拒绝非法报文段 非法连接请求

    SYN :同步序号,用于建立连接过程。

    —— syn=1 and ack=0 表示没有使用捎带的确认域

    —— syn=1 and ack=1 表示捎带一个确认域

    FIN :finish标志,用于释放链接。为1时表示发送方没有数据发送,关闭数据流。

  • 滑动窗口(window) : 标识发送端接收端的缓存大小,以此控制发送端发送速率,达到流量控制的目的

  • 校验和(checksum) :对报文头和报文数据以16位求和 在收发两端校验数据一致性

  • 紧急指针(urgent pointer) :当URG位为1时生效 标明报文中紧急字段的字节数

  • **可选项(TCP options) **:

TCP的三次握手

当应用程序想通过TCP与另一个应用程序通信时,会发送一个通信请求,这个请求会被发送到一个确切的通信地址,在双方握手之后,TCP将在两个应用程序之间建立一个全双工的通信,这个通信将占用两个应用之间的通信线路,知道一方或双方关闭。

全双工(Full-Duplex Transmissions): 是指交换机在发送数据的同时也能够接收数据,两者同步进行,这好像我们平时打电话一样,说话的同时也能够听到对方的声音。目前的交换机都支持全双工。即A给B发送信息时,B也可以给A发送信息在这里插入图片描述

三次握手流程
  1. 初始时,客户端和服务端处于关闭状态
  2. 服务端创建传输控制块,时刻保持准备接收其他连接请求,服务端进入监听状态
  3. 客户端创建传输控制块,向服务器发出连接请求,控制位的**同步标志(SYN)**置为1,**序号(sequence number)置为x。此时客户端处于同步已发送(SYN-SENT)**状态。此次的tcp报文消耗一个序号,且不能携带传输数据。这就是tcp的第一次握手。
  4. 当服务端收到连接请求,且同意连接,则会返回一个确认报文。控制位的**同步标志(SYN)**置为1,**确认标志(ACK)**置为1,**确认号(acknowledge number)**为x+1(由于第一次握手时,客户端序号为x,且消耗了一个序号,所以将ack置为x+1,指示客户端下次发送数据的起始序号),**序号(sequence number)为任意正整数y,此时服务端处于同步已收到(SYN-RCVD)**状态。此报文同样消耗一个序号,且不能携带数据。这就是tcp的第二次握手。
  5. 当客户端收到服务端的确认报文后,再次发送一个确认报文,控制位的**确认标志(ACK)**置为1,确认号(acknowledge number)置为y+1(由于之前服务端响应的确认报文的序号为y,且响应消耗一个序号,所以客户端将ack置为y+1,指示服务端下次发送数据的起始位置),序号置为x+1。此时客户端处于已建立连接状态(ESTAB-LISHED),当服务端收到这个报文,也处于已建立连接状态,双方可以进行通信。这就是tcp的第三次握手。
为什么需要三次握手才能建立连接?

为了初始化序号(sequence number)的初始值,作为后续数据处理的序号,以保证上层处理数据时,不会因为网络原因而乱序。即TCP会使用这个序号来拼接数据。

首次握手的隐患—SYN超时
  • 问题的原因分析
    服务端收到客户端发送的连接请求SYN之后,会发送一个SYN-ACK响应给客户端,如果客户端拒收此响应,服务端会不断尝试直到超时,在linux环境中默认会发起5此请求,每次请求间隔为上次间隔的2倍。即一共会等待1+2+4+8+16+32=63秒。
  • 可能会导致服务器收到SYN Flood攻击
    如果客户端恶意发送SYN请求后下线,最终导致服务器SYN队列塞满,无法响应正常的请求。linux下提供了tcp_syncookies参数(根source ip和destination ip和timestamp构造),在SYN队列满了之后,服务端会发送syn cookie,正常连接的客户端请求会回发这个cookie,这样即使syn队列满的情况下,依然可以建立连接。
保活机制

如果客户端由于故障未收到服务端响应报文。服务端尝试向对方发送保活报文,如果未收到响应则继续发送。
直至达到配置的最大保活探测数,此时判定对端为不可达状态,中断连接。

TCP的4次挥手

在这里插入图片描述

4次挥手流程
  • 第一次挥手:客户端发送FIN请求,结束标志置为1,序号u为最后一次发送数据序号+长度,用来关闭客户端到服务端的数据传送,此时客户端处于终止等待1(FIN-WAIT-1)状态。
  • 第二次挥手:服务端接收到客户端的FIN请求,向客户端发送一个ACK确认响应,确认标志置为1,序号v,确认号为u+1。此时服务端进入关闭等待(CLOSE-WAIT)状态,同时通知上层应用,服务端在关闭等待状态可能还会发送一些数据。客户端收到服务端的ACK响应,进入终止等待2(FIN-WAIT-2)状态,此时依然可以继续接受服务端发送的数据。
  • 第三次挥手:服务端发送FIN,通知客户端关闭数据传输,FIN=1,ACK=1,seq=w,ack=u+1。此时服务器进入最后确认(LAST-ACK)状态。
  • 第四次挥手:客户端收到FIN后,进入时间等待(TIME_WAIT)状态,同时发送一个确认请求,ACK=1,seq=u+1,ack=w+1。 服务端收到请求后直接进入关闭状态。客户端在等待2MSL时间之后进入关闭状态。
为什么会有TIME_WATI状态
  • 确保对端有足够时间收到ACK包
  • 避免新旧连接混淆

MSL是Maximum Segment Lifetime英文的缩写,中文可以译为“报文最大生存时间”,他是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。因为tcp报文(segment)是ip数据报(datagram)的数据部分,具体称谓请参见《数据在网络各层中的称呼》一文,而ip头中有一个TTL域,TTL是time to live的缩写,中文可以译为“生存时间”,这个生存时间是由源主机设置初始值但不是存的具体时间,而是存储了一个ip数据报可以经过的最大路由数,每经过一个处理他的路由器此值就减1,当此值为0则数据报将被丢弃,同时发送ICMP报文通知源主机。RFC 793中规定MSL为2分钟,实际应用中常用的是30秒,1分钟和2分钟等。
2MSL即两倍的MSL,TCP的TIME_WAIT状态也称为2MSL等待状态,当TCP的一端发起主动关闭,在发出最后一个ACK包后,即第3次握手完成后发送了第四次握手的ACK包后就进入了TIME_WAIT状态,必须在此状态上停留两倍的MSL时间,等待2MSL时间主要目的是怕最后一个ACK包对方没收到,那么对方在超时后将重发第三次握手的FIN包,主动关闭端接到重发的FIN包后可以再发一个ACK应答包。在TIME_WAIT状态时两端的端口不能使用,要等到2MSL时间结束才可继续使用。当连接处于2MSL等待阶段时任何迟到的报文段都将被丢弃。不过在实际应用中可以通过设置SO_REUSEADDR选项达到不必等待2MSL时间结束再使用此端口。

为什么需要四次回收才能断开连接

因为tcp连接是全双工的,所以要求通信两端必须各自发送FIN报文和ACK报文。


用户数据包UDP

UDP报文结构

在这里插入图片描述

  • 源端口
  • 目标端口
  • 数据长度
  • 校验和
UDP特点
  • 面向非连接
  • 不维护连接状态,支持广播相同的数据
  • 数据包报头只有8字节,开销小
  • 吞吐量只受限于数据生成速率 传输速率,机器性能影响
  • 尽最大能力交付,但不保证可靠交付,不需要维持复杂的连接状态表

TCP和UDP区别

TCPUDP
面向连接无连接
可靠,三次握手确认 重传机制不可靠
数据包有序,利用序号保证报文的序列交付无序
传输速度慢速度快
重量级 数据头较大轻量级 数据头较小

TCP的滑动窗口

RTT和RTO
  • RTT(Round Trip Time): 发送一个数据报到收到ACK响应所花费的时间。
  • RTO(Retransmission Time Out): 重传间隔时间

HTTP(HyperText Transfer Protocol) 超文本传输协议

简介

HTTP属于应用层协议,基于请求和响应的无状态的协议,基于TCP的连接方式

主要特点
  • C/S架构模式
    浏览器作为客户端,通过URL像web服务器发起请求。web服务端根据请求,向客户端浏览器发送响应信息
  • 简单快速
    通过GET POST…等方法和只当URL
  • 灵活
    可以发送任意类型数据,content type指定数据类型
  • 无状态
    客户端和服务端不会保存每次交互的信息,所以无法基于之前的信息处理当前的连接。
HTTP请求报文

在这里插入图片描述

HTTP响应报文

在这里插入图片描述

请求/响应的步骤
  1. 客户端和服务端建立TCP连接
  2. 客户端发起HTTP请求
  3. 服务端接受请求并返回HTTP响应
  4. 释放TCP连接
  5. 客户端解析响应内容
Q: 在浏览器地址栏输入URL,按下回车之后经历的流程
  1. DNS解析
    浏览器逐层根据DNS缓存解析URL得到对应的IP地址,得到IP直接返回不再继续。
    DNS缓存:浏览器缓存 - 系统缓存 - 路由器缓存 - IPS缓存 - 顶级域名缓存 - 根域名缓存
  2. 建立TCP连接
    基于IP地址和端口号建立客户端与服务端的TCP连接。经过3次握手(1.SYN 2.SYN-ACK 3.ACK)
  3. 发起HTTP请求
    应用层: 建立HTTP请求报文
    传输层:把报文分割成数据包segment,添加TCP首部信息(端口、序号、确认号、状态标志…)
    网络层:将TCP数据包作为数据,封装成IP数据包,添加IP首部信息(IP版本、长度、状态标志、IP地址…)
  4. 服务器处理请求并发回响应
  5. 断开TCP连接
    4次挥手(1.FIN 2.ACK 3.FIN-ACK 4.ACK)
  6. 客户端浏览器解析响应
HTTP状态码
类型
  • 1xx: 请求已接收,正在处理
  • 2xx: 请求成功处理完成
  • 3xx: 请求重定向
  • 4xx: 客户端错误
  • 5xx: 服务端错误
常见的状态码
  • 200 OK: 正产返回信息
  • 400 Bad Request: 客户端请求语法错误,不能被服务端解析
  • 401 Unauthorized: 请求未经授权
  • 403 Forbidden: 请求已接收,服务器拒绝处理
  • 404 Not Found: 请求资源不存在
  • **500 Internal Server Error:**服务端内部错误
  • 503 Server Unavailable: 服务器暂时无可用
Q:GET请求和POST请求的区别
GETPOST
请求参数追加在URL后面,以?开始每个参数之间以&分隔请求参数放在请求报文的请求体中,以Key: Value 形式
浏览器对url长度有限制无限制
对数据库操作符合一致性和安全性不符合
请求可以被缓存,可以被保存为浏览器书签不能
Cookie和Session
Cookie简介
  • 由服务端创建,发送给客户端,客户端以文本的形式存储
  • 客户端发送请求时,携带存储的cookie信息
  • 服务端接收到请求,解析cookie,并据此产生对应的行为以响应本次请求
Cookie设置和发送的过程

在这里插入图片描述

Session简介
  • 服务端机制,基于散列表保存会话信息
  • 解析请求中是否包含session id,存在直接检索并操作。不存在则创建一个新的session,并关联响应的session id;
  • 在响应中将session id发送给客户端保存
Session的实现方式
  • 基于Cookie实现
    在这里插入图片描述
  • 通过URL回写
    即服务端发送给浏览器页面的所有链接中,都附带jsession id参数。此时客户端点击任意链接,都会附带jsession id。
    tomcat的session实现方式是一开始同时使用cookie和url回写,当发现客户端支持cookie则使用cookie,并停止使用url回写。如果cookie被禁用,则使用url回写。
Q:Cookie和Session的区别
CookieSession
存放在浏览器存放在服务器
不安全安全
占用客户端资源占用服务端资源

HTTP和HTTPS

HTTPS(HyperText Transfer Protocol Security),是一种以计算机安全网络通信为目的的传输协议。通过在HTTP和TCP之间加入SSL或者TLS协议,保证通信的安全性。
SSL(Security Socket Layer),为网络通信提供安全及数据完整性的一种安全协议,是操作系统对外的API,在3.0版本后更名为TLS。SSL采用身份验证和数据加密保证网络通信的安全和数据完整性。

加密的方式
  • 对称加密:加密解密使用同一个密钥,安全性低,效率高。
  • 非对称加密:加密解密使用不同密钥,安全性高,效率低。
加密的过程
  1. 浏览器发送支持的加密算法
  2. 服务器选择某个支持的加密算法,以证书的形式发回浏览器
    证书包含信息:颁发机构 有效期 公钥 所有者 签名
  3. 浏览器验证证书合法性,生成随机密码并使用证书中的公钥加密(作为后续通信过程中对称加密的公钥),同时使用约定好的加密算法加密握手信息,并通过哈希算法生成消息摘要(确保数据完整性),并将这些消息发回服务器。
  4. 服务器使用私钥解密出公钥密码,使用公钥密码解密握手信息,并验证哈希后的消息摘要。然后加密新的握手信息发送回浏览器。
  5. 浏览器解密响应信息,并验真,之后通过浏览器生成的密码作为公钥,使用对称加密进行数据交互。
Q:HTTP和HTTPS的区别
HTTPSHTTP
需要证书不需要
数据密文传输明文传输
默认端口443默认端口80
有状态无状态
更安全 基于HTTP+SSL+认证+完整性保护不安全

Socket

进程唯一标识,本地可以通过PID唯一标识,网络通信中可以通过IP地址和端口号唯一标识。
Socket是对TCP/IP协议的抽象,是操作系统对外开放的接口。

Socket通信流程

在这里插入图片描述

Socket相关面试题

在这里插入图片描述

TCP socket
public class TCPServer {

    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(65432);

        while (true){
            Socket socket = serverSocket.accept();
            new LengthCalculatorTask(socket).start();
        }
    }
}
public class TCPClient {

    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("127.0.0.1", 65432);
        InputStream in = socket.getInputStream();
        OutputStream out = socket.getOutputStream();

        out.write("hello world".getBytes());

        byte[] buffer = new byte[1024];
        int len;
        len = in.read(buffer);
        System.out.println(new String(buffer, 0, len));

        in.close();
        out.close();
        socket.close();
    }
}
public class LengthCalculatorTask extends Thread {

    private Socket socket;

    public LengthCalculatorTask(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        try {
            InputStream in = socket.getInputStream();
            OutputStream out = socket.getOutputStream();

            int len;
            byte[] buffer = new byte[1024];

            len = in.read(buffer);

            String s = new String(buffer, 0, len);
            System.out.println(s);

            out.write(String.valueOf(s.length()).getBytes());

            in.close();
            out.close();
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}
UDP Socket
public class UDPServer {

    public static void main(String[] args) throws Exception {
        DatagramSocket socket = new DatagramSocket(65432);

        byte[] buffer = new byte[1024];
        DatagramPacket packet = new DatagramPacket(buffer, buffer.length);

        socket.receive(packet);

        byte[] data = packet.getData();

        String message = new String(data, 0, packet.getLength());
        System.out.println(message);

        byte[] responseContent = String.valueOf(message.length()).getBytes();
        DatagramPacket responsePacket = new DatagramPacket(responseContent, responseContent.length, packet.getAddress(), packet.getPort());
        socket.send(responsePacket);
    }
}
public class UDPClient {

    public static void main(String[] args) throws Exception {
        InetAddress address = InetAddress.getByName("127.0.0.1");
        DatagramSocket socket = new DatagramSocket();
        byte[] buffer = "hello world".getBytes();
        DatagramPacket packet = new DatagramPacket(buffer, buffer.length, address, 65432);
        socket.send(packet);

        byte[] data = new byte[1024];
        DatagramPacket receivedPacket = new DatagramPacket(data, data.length);
        socket.receive(receivedPacket);

        System.out.println(new String(receivedPacket.getData(), 0, receivedPacket.getLength()));
    }
}

总结

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值