嵌入式八股文-网络(速记版)

网络通信概述

        网络通信是位于网络中不同主机上的进程之间的通信,通常称为 socket IPC

        大概可以分为三个层次,如下所示:

        (1)硬件层:网卡设备,收发网络数据

        (2)驱动层:网卡驱动(Linux 内核网卡驱动代码

        (3)应用层:上层应用程序(调用 socket 接口或更高级别接口实现网络相关应用程序)

        在硬件上,两台主机都提供了网卡设备,也就满足了进行网络通信最基本的要求。

        网卡设备是实现网络数据收发的硬件基础。建立网络连接后两台主机之间才可以进行数据传输。网络数据的传输媒介有很多种,大体上分为有线传输(譬如双绞线网线、光纤等)和无线传输(譬如 WIFI、蓝牙、ZigBee、4G/5G/GPRS 等)。

        内核层提供网卡驱动程序,驱动底层网卡硬件设备,同时向应用层提供 socket 接口。

        应用层,应用程序基于内核提供的 socket 接口进行应用编程,实现自己的网络应用程序。

        需要注意的是,socket 接口是内核向应用层提供的一套网络编程接口,学习网络编程其实就是学习 socket 编程。

        除了 socket 接口之外,在应用层通常还会使用一些更为高级的编程接口,譬如 http、网络控件等,这些接口实际上是对 socket 接口的一种更高级别的封装。

数据的封装与拆封

        网络通信中,数据从上层到下层交付时,要进行封装;同理,当目标主机接收到数据时,数据由下层传递给上层时需要进行拆封。这就是数据的封装与拆封。

        当用户发送数据时,将数据向下交给传输层,但是在交给传输层之前,应用层相关协议会对用户数据进行封装,譬如 MQTT、HTTP 等协议,其实就是在用户数据前添加一个应用程序头部,这是处于应用层的操作,最后应用层通过调用传输层接口来将封装好的数据交给传输层。

        封装时每层都会加个首部结构。

IP 地址

        Internet 依靠 TCP/IP 协议,实现主机之间的互联。

        IP 地址用于标识互联网中 的每台主机的身份。

        IP 地址是软件地址,不是硬件地址,硬件 MAC 地址是存储在网卡中的

IP 地址的编址方式

        IP4是4个8位 。IPV6是8个16位。

        IPV4通常使用点分十进制表示。比如192.168.1.1。

        IP 地址中的 32 位实际上包含 2 部分,分别为网络地址主机地址,可通过子网掩码来确定网络地址和主机地址分别占用多少位。

IP地址的分类

        根据 IP 地址中网络地址和主机地址两部分分别占多少位的不同,将 IP 地址划分为 5 类,分别为 A、 B、C、D、E 五类。

        1、A 类 IP 地址

        A 类 IP 地址由 1 个字节网络地址和 3 个字节主机地址组成,网络地址的最高位必须为 0

        因此可知,网络地址取值范围为 0~127,一共 128 个网络地址。

        这 128 个网络地址中,其中 3 个网络地址用作特殊用途,因此可用的网络地址有 125 个。

        网络地址 0、127、10 属于特殊用途。

        网络地址 0 代表本网络,不能传送。

        网络地址 127 代表环回测试地址,localhost,发送的数据包会传给自己。

        网络地址 10 属于私有网络的范围。

        这里的/8代表前8位是网络地址

        A 类地址的第 1 字节为网络地址,其它 3 个字节为主机地址;

        每个网络地址后面跟主机地址,比如 1.0.0.0~1.255.255.255 ,网络地址固定,主机地址变化被称为子网地址。

        A类地址的子网地址又分为网络地址广播地址,网络地址是子网第一个地址,广播地址是子网最后一个地址。

        A类一般分配给大量主机的大型网络。

        2、B 类 IP 地址

        一个 B 类 IP 地址由 2 个字节的网络地址和 2 个字节的主机地址组成,网络地址的最高位必须是“10”。

        B 类地址中前 2 字节为网络地址,后 2 个字节为主机地址。

        (1)、网络地址最高位为10,范围128~191,共64个。子网全零网络地址,全一广播地址

        (2)、网络地址 127.16~127.31 是私有地址169.254 是保留地址

        如果你的 IP 地址是自动获取 IP 地址,而网络上找不到可用的 DHCP 服务器(动态主机配置)。就会得到保留地址其中一个 IP。

        3、C 类 IP 地址

        一个 C 类 IP 地址由 3 字节的网络地址和 1 字节的主机地址组成。

        网络地址最高位为“110”范围 192~223子网全零网络地址,全一广播地址

        C 类地址中的私有地址:192.168.X.X 是私有地址

        C类一般分配给局域网,比如校园网。

        4、D 类 IP 地址

        网络地址最高位为“1110”开始,它是一个专门保留的地址,它并不指向特定的网络,目前这一类地址被用在多点广播。

        D类不分网络地址和广播地址。

        5、E 类 IP 地址

        网络地址最高位为“1111”开始。为将来使用保留。全零 0.0.0.0 地址对应于当前主机。全1是当前子网的广播地址。

        E类也不分网络地址和广播地址。

TCP/IP协议簇

TCP/IP协议簇有很多协议,

        最核心的是网络层的 IP 协议,应用层的 TCPUDP协议。

        较核心的 地址解析协议APR,数据链路层用来根据IP获取MAC地址。

        MAC地址48位,表示为12个十六进制数,每个数用冒号:隔开。

                       网际控制报文协议 ICMP

        IP数据传输发生错误的时候,用ICMP报文封装错误传回主机。

        ICMP应用命令包括:Ping、Ipconfig、Netstat(检验网络连接情况)

基于TCP的应用层协议:

FTP           文件传输协议

Telnet        远程登陆

SMTP        邮件传输协议

DNS          域名服务

HTTP        超文本传输协议

基于UDP的应用层协议:

DNS         域名服务

TFTP        简单文件传输协议

SNMP       简单网络管理协议

RIP           路由信息协议

IPv4和IPv6的区别

IPv4是32位IP地址,而IPv6是128位IP地址。
IPv4是数字地址,用点分隔。IPv6是一个字母数字地址,用冒号分隔。

http、UDP报文结构

        首先明确一个概念,从应用层的http文本协议数据帧,到传输层 tcp/udp数据帧,到网络层 ip数据帧,到数据链路层 mac数据帧,每往下一层都会在HTTP协议的基础上封装一个对应的xx层头部数据。反复套娃。

        比如 HTTP文本协议的整个 请求行、请求头部、请求正文,当作TCP协议的数据帧,再加上TCP的60字节的固定头部,构成TCP的60字节固定头部+N字节数据的结构。

http报文

        http报文属于应用层协议、文本格式协议,报文中的每个字段都是一些ASCII码字符串。可以分为请求报文响应报文

        HTTP请求报文主要由请求行请求头部请求正文3部分组成。

        例如,GET /index.html HTTP/1.1。

请求报文:

        请求行 = 请求方法+URL+协议版本

        请求头部 = 头部字段:+内容

        请求内容 = 可选,一般JSON键值对

响应报文:

        响应行 = 协议版本+状态码+状态码描述符

        响应头部 = 头部字段:+内容

        响应内容 = 可选,一般JSON键值对

请求报文

响应报文

UDP报文

        端口号 + 16位UDP长度+16位UDP校验和+数据

TCP头部结构

TCP固定头部结构

        每个TCP报文段都包含着此报文段的TCP头部信息,用于指定源端端口、目的端端口以及管理TCP连接等。

        完整的TCP头部结构可分为20个字节的固定头部和最大40字节的头部选项两个部分。

        数据帧是60字节头部结构以外的N个字节。

32位端口号:包括了16位源端口号和16位目的端口号

32位序列号:单方向上传输的TCP报文段的序号为上次的序号值+1+此次报文段的数据字节大小

32位确认号:收到对方的报文段的序号值加1确认号ACK-1就是接收的字节数。

4位头部长度 + 6位保留 + 6位标志位 + 16位窗口大小

16位CRC校验和 + 16位紧急指针

        4位头部长度标识该TCP头部有多少个4字节(最小20字节,最大20+40=60字节)。

        6位标志位包含如下几项:

                SYN请求标志位        表示请求建立一个连接。携带SYN标志的称为同步报文段。

                ACK确认标志位        表示确认号是否有效。携带ACK的称为确认报文段。

                 FIN结束标志位         表示请求关闭连接。携带FIN标志的为结束报文段。                

                 RST复位标志位        表示要求重建连接。携带RST标志的称为复位报文段。

                URG紧急标志位        表示紧急指针是否有效。

                 PSH优先标记位        表示接收端立即从接收缓冲区读走数据。

        16位窗口大小:流量控制。常配合头部选项的Window Scale窗口放大因子一起使用,告诉对方本端的接收缓冲区还能容纳多少字节的数据。双方的窗口因子在三次握手的前两次发送给对方,后期通信过程不再声明。窗口大小被窗口放大因子到最大1GB.

        16位CRC校验和+16位紧急指针

             CRC校验,约定除数,做模二除法,除法运算时不进位借位。到被除数每一位被处理完。

             紧急指针标识紧急字节在数据流的首地址。会优先处理紧急报文。

        SYN、FIN、RTS报文也消耗序号,但不会携带应用层数据。 

        滑动窗口机制TCP的发送/接收缓冲区是个环形队列,当序号达到2^32-1(4GB)就会重新开始。如果缓冲区为空,序号就会从0开始。发送0,接收0+1应答,发送0+1,如此往复。发送方收到ACK报文后,根据ACK值将发送缓冲区对应内容释放掉。如果三次没收到ACK,就会重发。

        累计应答机制允许收到多条报文段后才返回一条总的ACK报文。报文到达的顺序可能和发送不一致,接收方收到报文后,先放到缓冲区,然后根据序号排序。如果中间某段报文丢失,之后的报文仍然可以正常接收,但返回给发送方的每一条ACK报文的ACK值都是丢失报文段的序号。

TCP头部选项字段

TCP头部最后的选项字段最多40字节,因为TCP头部最多60字节。

TCP头部选项的一般结构如图:

1字节的选项类型+1字节选项的总长度+n字节选项的具体信息

常见的TCP选项有7种:

kind = 0是选项表结束选项。

kind = 1是空操作选项,一般用于将TCP选项的总长度填充为4字节整数倍。

kind = 2是最大报文长度选项。TCP连接初始化时,通信双方使用该选项来协商最大报文段长度(Max Segment Size,MSS)

kind = 3是窗口扩大因子选项。和MSS选项一样,窗口扩大因子选项只能出现在同步报文段中,否则将被忽略。当连接建立好之后,每个数据传输方向的窗口扩大因子就固定不变了。

kind = 4是是否支持SACK。在连接初始化时,表示是否支持SACK技术。在建立连接时确认是否支持SACK。

kind = 5是SACK实际内容。其实就是成功接收的数据段范围,发送方根据对方已接受的序列号范围自行判断丢失了哪些。SACK只针对失序报文段,SACK是为了避免快速重传机制带来的TCP性能影响。

kind = 8是时间戳选项。该选项提供了较为准确的计算通信双方之间的回路时间(Round Trip Time,RTT)的方法,从而为TCP流量控制提供重要信息。

请说一下socket网络编程中客户端和服务端用到哪些函数?

1)服务器端函数

//套接字描述符可以像文件描述符一样read()

socket()    返回套接字描述符

int socket(int domain, int type, int protocol);

协议域

        AF_INET                IPv4 地址族

        AF_INET6              IPv6 地址族

        AF_UNIX                UNIX 域套接字,用于在同一台计算机上的进程间通信。

        AF_PACKET           原始套接字,用于对数据链路层数据包进行直接操作。

        AF_NETLINK          用于与 Linux 内核通信的协议域

套接字类型

        SOCK_STREAM     字节流套接字(TCP)

        SOCK_DGRAM       数据报套接字(UDP)

        SOCK_RAW            原始套接字,用于直接访问网络层数据包(未经协议栈处理的)

        SOCK_SEQPACKET 字节流套接字,但保留了数据包i的边界

        SOCK_RDM            UDP,但保证数据不会重复

        

协议

                0                       系统根据地址域和套接字类型自动选择合适的协议

        IPPROTO_TCP        指定使用 TCP协议

        IPPROTO_UDP        指定使用UDP协议

        IPPROTO_ICMP       指定使用ICMP协议。通常用于网络诊断

        IPPROTO_RAW        指定使用原始IP协议。允许直接访问网络层数据包

bind()                将地址与套接字绑定

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);//错误返回负数

套接字描述符

socketaddr结构体指针

        在实际的 Socket 编程中,通常会用 `sockaddr_in` 结构体来存储网络地址信息,

        然后将其转换为通用的 `sockaddr` 结构体传递给 Socket 函数,

        如 `bind()`、`connect()`、`accept()` 等函数。

        struct sockaddr {

                        unsigned short sa_family; // 地址族。AF_INET表示IPV4

                        char sa_data[14]; // 地址数据,包括地址信息

                        };

        struct in_addr {

                         in_addr_t s_addr; // IPv4 地址

                        };

        struct sockaddr_in {

                        short sin_family; // 地址族,AF_INET表示IPV4

                        unsigned short sin_port; // 端口号  如 htons(8080)

                        struct in_addr sin_addr; // IPv4 地址        

                                        //        INADDR_ANY 接收任意地址的连接

                                         //       INADDR_LOOPBACK 本机自身的地址

                        char sin_zero[8]; // 未使用,填充字段

                      };

socketaddr结构体长度

                用sizeof()得到

listen()        将套接字设为监听模式,等待连接请求。

int listen(int sockfd, int backlog);//一直监听直到发生错误或有连接到来。

套接字描述符                              

同时可以处理的连接请求数量

accept()        接收客户端连接请求,返回一个新的套接字用于数据收发

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

套接字描述符

socektaddr结构体指针

socketaddr结构体长度

connect()        发起与远程主机的连接

int   connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

套接字描述符

sockaddr结构体指针

socketaddr结构体指针长度

send()        向socket发送数据                 //文件Io的write也可以用 不会携带\0

ssize_t send(int sockfd, const void *buf, size_t len, int flags);//返回发送成功的字节,失败-1

套接字描述符

发送缓冲区指针 //如果是传结果体可以直接&struct来序列化

要发送的字节数

指定发送操作的选项

       

recv()       从socket读取数据 //文件Io的read也可以用 均不会自动给添加结束符'\0'

ssize_t recv(int sockfd, void *buf, size_t len, int flags);//flags=0代表默认阻塞

recv默认阻塞,buffer值NULL则等待,可用一些包的函数设置套接字阻塞/非阻塞

返回接收到的字节数,返回0代表连接关闭,返回-1代表发生错误,可通过errno调出返回值

perror(errno)//打印错误码 printf("%d",errno)也可

套接字描述符

接收缓冲区指针

要接收的字节数

指定接收操作的选项

close 关闭socket连接 

int close(int fd);                        //关闭成功返回0,失败返回-1

套接字描述符

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>

#define PORT 8080
/*服务端*/
int main() {
    int server_fd, new_socket;
    struct sockaddr_in address;
    int addrlen = sizeof(address);
    char buffer[1024] = {0};
    char *hello = "Hello from server";

    // 创建套接字
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }

    address.sin_family = AF_INET;         //设置地址族
    address.sin_addr.s_addr = INADDR_ANY;
  
    //将主机字节序的16位无符号整数转换为网络字节序。不同系统可能使用不同大小端字节序。
    address.sin_port = htons(PORT);

    // 绑定套接字到指定端口
    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }

    // 监听传入的连接
    if (listen(server_fd, 3) < 0) {
        perror("listen");
        exit(EXIT_FAILURE);
    }

    // 接受连接
    if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
        perror("accept");
        exit(EXIT_FAILURE);
    }

    // 从客户端接收数据
    read(new_socket, buffer, 1024);
    printf("Client: %s\n", buffer);

    // 向客户端发送数据
    send(new_socket, hello, strlen(hello), 0);
    printf("Hello message sent\n");

    return 0;
}

/*
`perror` 是一个 C 标准库函数,
用于将由标准库函数产生的错误代码(保存在全局变量 `errno` 中)打印成人类可读的错误消息
到标准错误输出(stderr)。它的原型定义在 `<stdio.h>` 头文件中。
*/
/*
`socklen_t` 是一个数据类型,通常用于表示套接字地址结构的长度。
它通常被定义为 `unsigned int` 或者 `unsigned long` 类型,足够大以容纳套接字地址结构的长度
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>

#define PORT 8080

int main() {
    struct sockaddr_in serv_addr;
    char *hello = "Hello from client";
    char buffer[1024] = {0};
    int sock = 0;

    // 创建套接字
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        printf("\n Socket creation error \n");
        return -1;
    }

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT);    //将主机字节序转换为网络字节序
    serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");

    // 连接到服务器
    if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
        printf("\nConnection Failed \n");
        return -1;
    }

    // 向服务器发送数据
    send(sock , hello , strlen(hello) , 0 );
    printf("Hello message sent\n");

    // 从服务器接收数据
    read( sock , buffer, 1024);
    printf("Server: %s\n",buffer);

    return 0;
}

TCP常见粘包等问题思路,UDP没有粘包现象,为何

//send(socketClientCfd, "Login", strlen("Login"), 0);	
send(socketClientCfd, "Login", strlen("Login")+1, 0);	
sprintf(buffer,"%d",userPhoneLogin);
send(socketClientCfd,buffer,1024,0);//发送手机号

        这里的两个send在接收时出现了粘包,原因是第一个send直接使用字符串常量,在strlen("login")处没有给结束符\0留位置

        牢记send和recv的字节数应严格相同,如果发送端发送字节数>接收端接收字节数,可能导致数据被拆分,如果发送端发送字节数<接收端接收字节数,可能导致接收端缓冲区存在数据残留,影响下一次读取。

初始序列号 ISN 是如何产生的

        初始序列号 ISN 是根据 时钟、IP、端口号 随机生成的。可以用MD5这类的Hash算法。

既然 IP 层会分片,为什么TCP层还需要MSS

        MTU:一个网络包的最大长度,以太网中一般为1500字节。

        MSS:除去IP和TCP头部后,一个网络包能容纳的 TCP 数据最大长度。 

        当 IP层 有一个超过 MTU 大小的数据(IP头部+TCP头部+数据)要发送,那么IP层就会进行分片,把数据分成若干片,保证每一个分片都小于MTU。分片后由目标主机的IP层组装后,再交给上一层TCP传输层。

        这种做法存在隐患,如果一个IP分片丢失,整个IP报文都要重传。

        因为 IP 层本身没有超时重传机制,它由传输层的 TCP 来负责超时和重传。
        当某一个 IP 分片丢失后,接收方的 IP 层就无法组装成一个完整的 TCP 报文(头部 + 数据),也就无法将数据报文送到 TCP 层,所以接收方不会响应 ACK 给发送方,因为发送方迟
迟收不到 ACK 确认报文,所以会触发超时重传,就会重发「整个 TCP 报文(头部 + 数据)」。
        因此,可以得知由 IP 层进行分片传输,是非常没有效率的。
        所以,为了达到最佳的传输效能 TCP 协议在建立连接的时候通常要协商双方的 MSS 值,当
TCP 层发现数据超过 MSS 时,则就先会进行分片,当然由它形成的 IP 包的长度也就不会大于MTU ,自然也就不用 IP 分片了。

TCP/UDP

MSL    最大报文存活时间

TTL     最大路由跳转次数

TCP怎么保证可靠性

1. 序列号、确认应答、超时重传

连接建立以后发送方发送数据,首次数据会携带ISN初始序列号,此后每次单方向上的序列号为上个序列号+上次报文在整个字节流中的偏移量,ACK确认号为接收到的报文序列号+1。如果发送迟迟未收到确认应答,那么可能是发送的数据丢失,也可能是确认应答丢失,这时发送方会在等待一定事件后进行重传。发送方等待确认应答的时间一般为2*RTT+一个偏差值

2. 窗口控制与快速重传(重复确认应答)

TCP会利用滑动窗口来控制流量,避免发送数据过多接收方无法处理。滑动窗口机制允许接收方通知发送方当前可以接收的数据量,发送方根据这个窗口大小来控制发送的数据量。在一个窗口大小内,发送方发送数据后无需等待确认。不使用窗口控制,每一个没收到确认应答的数据都要重发。

使用窗口控制,如果数据段1001-2000丢失,后面数据每次传输,确认应答都会不停地发送序号为1001的应答,表示我要接收1001开始的数据,发送端如果收到3次相同应答,就会触发重传机制。

简述一下TCP建立连接和断开连接的过程

TCP建立连接和断开连接的过程
三次握手

 1、Client首先发送同步报文段。将请求标志位SYN置1,同时随机产生一个序列号Seq_Client,并将该数据包发送给Server以请求连接,Client进入SYN_SENT状态

2、Server回复确认报文段,将SYN和ACK都置为1,应答号ack=Seq_Client+1,同时随机产生一个序列号Seq_Server,将该数据包发送给Client以回复请求,Server进入SYN_RECV状态

3、Client收到确认后,检查收到的报文应答号ack是否为Seq_Client+1,应答标志位ACK=1,正确的话就把ACK置1,回复一个应答号为Seq_Server+1的确认报文段。Server收到后检查应答号和应答标志位,正确则连接建立成功,Client和Server进入ESTABLISHED状态,完成三次握手。

四次挥手

TCP连接是全双工通信,每个方向都必须要单独进行关闭。

1、Client发送FIN标志位=1的结束报文段,并停止发送数据,进入FIN_WAIT_1状态

2、Server发送一个确认报文段给客户端,进入CLOSE_WAIT状态。Client收到后进入FIN_WAIT_2状态。

3、Server发送一个结束报文段给客户端,进入LAST_ACK状态。

4、Client返回一个ACK报文,进入TIME_WAIT状态,等待2MSL(报文段往返时间)后关闭连接。

为什么是三次握手?

三次握手可以防止已失效的SYN连接请求报文段被送到服务端导致错误连接。一个例子就是客户端发送了一次连接请求,延迟传送到服务端,期间又发送了一次请求并成功连接,如果只两次握手服务端会认为客户端又传来了一个新的连接请求,并重新连接,导致服务器资源浪费。

还有就是客户端发送连接请求后就挂掉了,服务端这时建立连接也会浪费资源

为什么是四次挥手?

        TCP协议是全双工通信,这意味着客户端和服务器都可以向彼此发送和接收数据,因此关闭连接是双方都需要确认的行为。

        假设只有三次挥手,经历了客户端的FIN请求,服务端的应答,服务端的FIN请求,此时TCP连接处于半关闭状态(Half-Close)状态。如果服务端还有数据发送给客户端,客户端是接收不到的。

为什么等待2MSL后关闭连接?

服务器发送了FIN+ACK给客户端,客户端返回ACK后等2MSL后断开连接,是确保服务器能够收到最后一次应答报文段,因为服务器没收到的话会重发FIN+ACK重启第三次挥手。

TCP、UDP的特点是什么

TCP具有可靠、稳定的优点,三次握手四次挥手建立稳定的通信连接和释放流程,还有连接确认滑动窗口快速重传拥塞控制机制。缺点是效率低,维护连接消耗资源大。TCP适用于文件传输、邮件传输等场景。

UDP是无状态传输协议,数据传输快但是不稳定。适用于视频、语音等场景。

什么是TCP拥塞控制?达到什么情况开始减慢增长速度?

如果把窗口定的很大,发送端连续发送大量的数据,可能会造成网络的拥堵。TCP为了防止这种情况进行了拥塞控制

TCP拥塞控制由4个核心算法组成。"慢启动"、"拥塞避免"、"快速重传"、"快速恢复"。

慢启动:慢启动是TCP连接初始化时的一种算法,用于TCP连接时增加拥塞窗口的大小。拥塞窗口初始大小通常为1,每收到一个ACK报文段拥塞窗口的大小就*2,直到达到慢启动阈值

拥塞避免:拥塞避免算法用于避免网络拥塞并保持网络的稳定性。一旦拥塞窗口大小达到慢启动阈值,发送方就会进入拥塞避免阶段,此时拥塞窗口的大小由收到一个ACK报文段*2改为+1,以此来避免拥塞。

快速重传:遇到3次序列号相同的ACK应答报文时,代表该序列号报文丢失,就会触发重传。

快速恢复:当发送方触发快速重传后,会将拥塞窗口减半,然后进入快速恢复阶段。此时收到一个ACK报文段拥塞窗口大小增长恢复到*2,直到达到阈值。

拥塞窗口是同一时间服务器能处理的数据量的上限

OSI七层模型和TCP/IP协议栈四层模型的对应关系

OSI七层模型和TCP/IP四层模型的对应关系

OSI参考模型有7层,从上到下分别为:

(应用层、表示层、会话层)、运输层、网络层、(链路层、物理层)

应用层:在应用层规定数据格式                          HTTP\FTP\DNS

表示层:负责数据的格式转换和加密                   JPEG/ASCII/JSON

会话层:负责建立和管理会话连接                       RPC/NFS

传输层:负责流量控制和错误检测                        TCP/UDP

网络层:数据包的路由选择和转发                        IP/ARP/ICMP

数据链路层:将字节组装成数据帧,MAC寻址      MAC/VLAN/PPP

物理层:数据比特流在物理条件下传输                IEE/CLOCK/RJ45

TCP/IP模型有4层,从上到下分别为:

应用层、运输层、网络层、网络接口层

应用层:包括各种应用协议如HTTP、FTP、SMTP等

传输层:负责端到端传输,TCP协议和UDP协议

网络层:负责主机之间通信,IP协议

网络接口层:定义数据在物理介质上传输的方式,以太网、WIFI等

请你说说TCP四层模型,状态转移

四层TCP/IP模型,包括应用层、传输层、网络层、网络接口层

三次握手:

        客户端发送SYN建立连接,进入SYN_SEND状态

        服务端回复ACK,并发送SYN,进入SYN_RECV状态

        客户端回复ACK,双方进入ESTABLISHED状态

         客户端- SYN_SEND、ESTABLISHED

         服务端- SYN_RECV、ESTABLISHED

四次挥手:        

        客户端发送FIN请求断开连接,进入FIN_WAIT1状态

        服务端回复ACK,进入CLOSE_WAIT状态,

        客户端接收ACK,进入FIN_WAIT2状态

        服务端发送FIN,进入LAST_ACK状态

        客户端回复ACK,进入TIME_WAIT状态,等待2MSL后关闭连接

        客户端- FIN_WAIT1、FIN_WAIT2、TIME_WAIT

        服务端- CLOSE_WAIT、LAST_ACK 

请你说说对TCP连接中time_wait状态的理解

        假设不存在time_wait状态,四次挥手后直接关闭连接,然后快速重新创建连接,上次没传输完的信息是无法被分辨的,会导致诡异现象。等2MSL后旧的数据包超过生命周期会被丢弃,传输更稳定。

TCP三次握手什么时候开始传输数据?

        在TCP三次握手的过程中,理论上第三次握手(客户端发送ACK确认服务器的SYN-ACK)可以携带数据。但是,前两次握手(SYN和SYN-ACK)通常不携带应用层数据。

        这是因为TCP连接在第三次握手完成之前并不认为是完全建立的。只有当三次握手全部完成后,连接才被认为是稳定的,数据传输才真正开始。在这个阶段之前,携带数据存在着一些风险,其中最主要的是,如果连接建立过程中出现问题,那么在握手阶段传输的数据可能会丢失,因为TCP的重传机制还没有开始工作。

TCP/IP数据链路层的交互过程是什么样的?

        数据链路层使用MAC地址作为通信目标。数据包到达网络层准备往数据链路层发送的时候,首先会去ARP缓存表里查找ip对应的MAC地址,查到了就把IP对应的MAC地址封装到链路层数据包的包头;如果没有找到,就会发起广播到局域网中,请求具有特定IP地址的设备回复自己的MAC地址,一旦收到回复,就会更新ARP缓存表中的映射关系。

ARP,Address Resolution Protocol,地址解析协议

ARP缓存表中的每一项都包含以下信息:

- IP地址:设备的IP地址

- MAC地址:对应设备的MAC地址

- 接口:设备连接网络的接口

TCP/IP协议传递到IP层怎么知道报文该给哪个应用程序,它怎么区分UDP报文和TCP报文

IP层使用目标端口号确定报文的去向。

IP协议头中的报文的标识字段可以确定是TCP报文还是UDP报文:UDP 17、TCP 6

请你介绍一下UDP的connect函数

UDP协议本质上是无连接的,每个数据包都独立发送不需要在传输数据之前建立连接。

因此,在UDP中调用connect函数并不会像TCP一样建立连接,而是在内核中记录下目标地址和端口,便于后续使用。

一旦UDP套接字调用了connect函数,那么这个UDP连接就变成了一对一的连接。一旦变成一对一的连接,后续系统调用send和recv之类也就和TCP那一套类似了。

1)调用connect函数后,不能再给输出操作指定IP地址和端口号。也就是不能再使用sendto,而改用send或write。

2)不必使用recvfrom来获取数据报文的发送者,而改用read、recv或recvmsg。在一个已连接的UDP套接字上,由内核为输入操作返回的数据报只有哪些来自connect指定协议地址的数据报。这样就限制了一对一的传输。

3)由已连接的UDP套接字引发的一部错误异步错误会返回给它们所在的进程,而未连接的UDP套接字不接受任何异步错误。

浏览器输入URL到页面显示发生了什么

浏览器将URL解析为IP地址,涉及域名就要用到DNS协议。首先主机会查询DNS的缓存,如果没有就给本地DNS发送查询请求。DNS查询包括递归查询和迭代查询。如果是迭代查询,本地的DNS服务器会向根域名服务器发送查询请求,根域名服务器告知该域名的一级域名服务器,然后本地服务器给该一级域名服务器发送查询请求,然后依次类推直到查询到该域名的IP地址。DNS服务器是基于UDP的,因此会用到UDP协议。

得到IP地址后,浏览器与服务器建立一个HTTP连接。HTTP生成一个GET请求报文,将该报文交给TCP层处理,所以还会用到TCP协议。如果采用https还会先对http数据进行加密。TCP层如果有需要先将HTTP数据包分片,TCP数据包然后会发送给IP层,用到IP协议。IP层通过路由跳转到目标地址。在一个网段内的寻址是通过以太网协议实 现(当然也可以是其他物理层协议,如PPP,SLIP)以太网协议需要MAC地址,涉及ARP协议。

HTTPS和HTTP的区别

        在HTTP连接的基础上,HTTPS建立连接的过程会把自己的数字证书给客户端,客户端验证有效性后会生成一个随机的对称密钥用于加密后续的数据传输(TLS加密)。

        HTTP是明文传输,HTTPS是经过TLS加密的

        HTTPS在TCP三次握手以后,还需要进行SSL的握手

        HTTPS协议需要服务端申请证书,浏览器端安装对应的根证书

        HTTP协议端口是80,HTTPS协议端口是443

        HTTPS更安全,但握手阶段延时高,需购买CA证书和加解密,占用CPU资源多,部署成本高

IP地址

        每个IP地址包含两个ID,即网络ID和主机ID

        A类 一个网络字节,三个主机字节        用于广域网  主机号数量为2^24-2,去除255和0

        B类 两个网络字节,两个主机字节       

        C类 三个网络字节,一个主机字节        用于局域网  主机号数量为2^8-2

子网掩码

        IP地址&子网掩码用来标识IP地址哪些位是网络ID,哪些位是主机ID

        比如

                192.168.1.128

             & 255.255.255.0

        得到192.168.1.0,该网络为C类,3个字节网络ID,一个字节表示主机ID

        还有种表示比如192.168.2.128/24 其中24表示子网掩码是连续的24个1,即255.255.255.0

IPV4和IPV6的区别

1)协议地址的区别

        IPV4具有32位地址长度,IPV6具有128位地址长度

        IPV4是用十进制小数表示二进制数,IPV6是用十六进制表示的二进制数

IPV4:192.168.1.1           IPV6:2001:0db8:85a3:0000:0000:8a2e:0370:7334

 2)地址解析协议

        IPV4使用ARP协议映射到MAC地址

        IPV6使用NDP协议映射到MAC地址  NDP,邻居发现协议

3)身份验证和加密 

        IPV6提供身份验证和加密,IPV4不提供

4)数据包最小值和包头长度的区别

IPV4协议数据包最小值为576个字节;IPV6协议的数据包最小值为1280个字节。

IPV4包头长度为20~40字节,IPV包头长度固定40个字节。

SOCKET

请问你有没有基于SOCKET做过开发?具体网络层的操作该怎么做?

基于TCP的socket

        服务端:socket-bind-listen-accept

        客户端:socket-connect

        结构体:addr和addr_in,用来绑定Ip地址和端口等属性

        htons把16位本地字节序转网络字节序(大端),ltons把32位本地字节序转网络字节序(小端)

        ntons把16位网络字节序转本地字节序

        send/write和recv/read来做缓冲区的读写

        close关闭文件描述符

基于UDP的socket

        服务端:socket-bind-recvfrom-sendto

        客户端:socket-sendto-recvfrom

        close关闭文件描述符

客户端/服务端

URI(统一资源标识符)和URL(统一资源定位符)之间的区别

URL:

        URL统一资源定位符(Uniform Resource Locator),其实就是“网址”

        协议类型 : // 认证信息 @ 服务器地址 : 端口号 / 带层次的文件路径 ? 查询字符串 # 片段标识符

        htttp : // user:pass @ www.example.jp : 80 / dir/index.html ? uid=1 # ch

URI:

        URI统一资源标识符(Uniform Resorce Identifier),就是某个网络协议方案表示的资源的定位标识符。比如HTTP网址就是HTTP协议下的URI

        URL是URI的子集。

为什么服务器易受SYN攻击?

        SYN攻击是DDos攻击的一种,原理是伪造源地址对服务器发送SYN请求,服务器需要回应SYN+ACK包,而真实地址由于并未发送连接请求不会对服务器做出回应,可能造成目标服务器中的半开连接队列被占满,从而阻止其他合法用户进行访问。SYN攻击数据包的特点是源地址发送大量SYN包,并缺少三次握手的最后一步握手ACK回复。

防护措施:

        Syn Cache技术。SYN报文来了,不着急去分配资源处理连接,而是简单回复一个ACK报文,并在一个HASH表中缓存这种半开连接,直到收到正确的连接再分配资源处理。

        Syn Cookie技术。Syn Cookie使用特殊的算法生成Seq序列,这种算法考虑到了对方的IP、端口、己方IP、端口和数据段长度、传输时间等信息,在收到对方的报文后会计算这些数据是否对应,从而决定是否分配资源

        Syn Proxy防火墙。对到来的SYN请求进行验证以后才放行。

请问Server端监听端口,但还没有客户端连接进来,此时进程处于什么状态?

编程模型用的是阻塞式IO还是非阻塞式IO,如果是阻塞式IO就是阻塞状态,如果是非阻塞式IO那种IO复用的情况就是运行状态

数字证书是什么,里面包含哪些内容?

数字证书由认证中心(CA)颁发。根证书是认证中心与用户建立信任的基础。认证中心是一种管理机构,用户将自己的私用密钥对和公共密钥对传送给认证中心,认证中心核实身份后给用户颁发一个数字证书。在用户使用数字证书之前必须下载和安装。

请你说一下GET和POST的区别

get参数通过url传递,post放在request body中

get请求在url中的参数有长度限制,而post在request body中的参数无限制

get参数直接暴露在url中,相比post不安全

get请求和post请求本质上就是tcp连接,但get请求直接把请求头和请求参数放一起打包成一个数据包,而post请求会把请求头和请求体分两个数据包传送。

Python八股文是指在面试或编程竞赛中常见的一些固定问题和解题思路。以下是一个常见的Python八股文大纲: 1. 基础语法: - 变量、数据类型、运算符、控制流程等基本语法要点; - 列表、字典、元组、集合等常用数据结构的使用; - 函数、类、模块的定义和使用。 2. 文件操作: - 打开、读取和写入文件的方法; - 文件的读写模式和文件指针的操作; - 异常处理和文件关闭。 3. 网络编程: - 常见网络协议(如HTTP、TCP/IP)的基本概念; - 使用socket库进行网络通信; - 客户端和服务器的基本交互过程。 4. 数据库操作: - 数据库的连接和关闭; - SQL语句的基本使用; - 使用Python库进行数据库操作。 5. 并发与异步: - 多线程和多进程的基本概念; - 使用threading和multiprocessing库进行并发编程; - 异步编程的基础知识和asyncio库的使用。 6. Web开发: - 前后端分离与后端渲染的理解; - 常用Web框架(如Flask、Django)的使用; - RESTful API的设计与实现。 7. 数据分析与机器学习: - 常用数据处理和分析库的使用(如NumPy、Pandas); - 机器学习算法的基本原理和常见库的使用(如Scikit-learn、TensorFlow); - 数据可视化和模型评估方法。 这只是一个简单的大纲,具体问题和应用场景可能还有其他需要掌握的知识点。在面试或比赛中,了解并熟练掌握这些基本知识点,能够灵活运用,才能更好地展示自己的编程能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大象荒野

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值