目录
------大部分采用问答式驱动复习------
信号
信号的基本概念
什么是信号?信号与中断的区别?信号的来源有哪些?信号的种类有哪些?
如何查看信号种类?每类信号的特点是什么?信号的处理方式有哪三种?
信号是一种异步通信方式,用于通知进程发生了什么事,是进程通信的方式之一;信号是进程间的,中断是硬件和操作系统间的一种机制;信号的来源有用户交互、错误和异常、系统状态变化、显示信号发送;信号的种类大致分为标准信号(1-31)和实时信号(34-64);用kill -l查看信号种类。非实时信号也就是标准信号,不排队、可能丢失,而实时信号需要排队;信号处理的方式有忽略、默认、自定义。
信号的递送流程(核心理解)
首先是信号的产生,然后给内核态,内核态分辨和处理信号再递送给对应的进程,给task_struct也就是PCB,然后看类型递送给未决信号集(实时信号会进链表)和阻塞集合,最后内核态返回用户态时检查未决信号集,检查后采用忽略、默认还是自定义,详细可以见Linux07(信号01)。
信号注册函数
signal函数
signal函数的传参是怎么样的?函数指针、指针函数、数组指针、指针数组的区别?
一个信号可以注册不同的信号处理函数吗?多个信号可以注册一个信号处理函数吗?不同的信号是否可以注册不同的信号处理函数?一个信号在触发并且处理的时候,相同的信号来了会怎么样?一个信号在触发并且处理的时候,不同的信号来了会怎么样?一个信号在触发并且处理的时候,相同的信号来了多次会怎么样?
signal函数的传参是,第一个是信号的类型,第二个参数是具体的信号处理函数(可忽略、自定义)。函数指针 本质是一个指针是一个指向函数的指针,例如 void (func)(int a);指针函数是一个函数,返回值是一个指针,int func(inta);数组指针 本质是一个指针,指向数组的指针,char (*buf)[10];指针数组 本质是一个数组char *buf[10],用来存储一个个指针。
一个信号可以注册不同的信号处理函数,后注册的会覆盖先注册的。多个信号可以注册同一个信号处理函数。不同信号也可以注册不同的信号处理函数。
一个信号在触发并处理的时候,相同信号来了会被阻塞,放入未决信号集中置1,表示该信号处于未决状态。
一个信号在触发并处理的时候,不同信号来了会中断当前在处理的信号,转而执行新信号处理函数,处理完新信号再返回。
一个信号在触发并处理的时候,相同信号来了多次会至多再执行一次,然后后面的全部丢弃,也就是包括开始在触发的那次加后面来的一次,共两次。
sigaction函数
函数有几个参数,每个参数是什么类型?第二个重要参数:结构体struct sigaction包含哪些成员?sigset_t底层是什么数据结构?操作这个数据结构对应的函数有那几个?
sigset_t 的底层数据结构是位图 ,公有六个函数,分别是sigemptyset函数、sigaddset函数、sigdelset函数、sigismember 函数、sigprocmask函数、sigfillset函数。其余问题可参考Linux08(信号02)。
与信号相关的其他函数
sigpending函数用于检查当前进程的未决信号集,即那些已经发送给进程但由于某些原因(通常是阻塞)而未被处理的信号,这个函数可以用来确定哪些信号已经被产生但没被进程捕获或忽略。sigprocmask函数用于在系统中检查和更改进程的信号屏蔽字(即信号掩码mask),信号掩码确定了哪些信号可以递送给该进程,哪些信号被阻塞,和sigaction函数所设置的sa_mask阻塞机制(局部阻塞)不同,sigprocmask是全程屏蔽阻塞。sigsuspend函数、kill函数、pause函数、alarm函数、setitimer函数。部分解释可以参考Linux08(信号02)。
线程
线程基本概念
什么是进程?什么是线程?线程与进程的区别是什么?同一个进程中的线程会共享什么、每个线程会独享什么?
为何不使用多进程编程,而要使用多线程编程?
进程是资源分配的最小单位,在没有线程的时候,也是资源调度的基本单位。线程是CPU调度的最小单位。线程与进程的区别主要体现在资源、调度、通信、独立性、创建/销毁上,资源上,进程拥有独立的地址空间和系统资源而线程共享进程的资源,调度上,进程开销大,需要切换地址空间,而线程在同一进程切换,通信上,进程有管道、消息队列、共享内存、信号等,线程直接共享内存,独立性上,一个进程的崩溃不影响其他进程,而一个线程崩溃可能导致整个进程崩溃;同一进程中的线程会共享进程的堆空间、代码段、数据段、文件描述符表、信号处理方式等,每个线程独享自己的栈空间、线程id、程序计数器等。
线程的创建、切换、销毁的开销都比进程小;线程直接通过共享内存交换数据,无需陷入内核。可参考Linux09(线程)。
线程基本操作
线程的基本操作主要有创建、等待、主动退出、被动退出、资源清理(可以参考Linux09(线程))。
互斥锁
互斥锁的基本概念
为什么需要互斥锁?互斥锁是什么?互斥锁有哪几种状态?什么是饥饿?什么是死锁?
多个进程或者线程并发访问共享资源的时候,由于不确定谁先访问,所以需要互斥锁来保证数据的正常访问和修改,就是保证同一时刻只有一个线程访问共享资源。互斥锁是一种用于多线程编程的同步机制。互斥锁有未锁定、锁定、等待三种状态。饥饿就是指线程由于某种原因无法获得所需的锁,导致长时间无法运行。 死锁是指线程在执行过程中,由于竞争资源的使用不当造成的一种永久阻塞的现象。
锁的使用
互斥锁的数据类型是什么?如何给锁进行初始化?如何销毁互斥锁?上锁函数是什么,使用上锁函数需要注意什么?解锁函数是什么,使用解锁函数需要注意什么?尝试上锁函数是什么,使用该函数与上锁函数有哪些区别?
互斥锁的数据类型是 pthread_mutex_t。用pthread_mutex_init函数来初始化(动态初始化),还有一种静态初始化,用一个 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER。使用pthread_mutex_destroy函数来销毁锁,只能销毁已经初始化但未上锁的互斥锁。上锁函数是pthread_mutex_lock函数,使用上锁函数要注意不要重复上锁,一定要和解锁配对。解锁函数是pthread_mutex_unlock函数,也是不要重复解锁,且只能由持有该锁的线程来解锁。尝试上锁函数是pthread_mutex_trylock函数,使用该函数如果没抢到锁不会阻塞会继续执行。
条件变量
条件变量的基本概念
为什么使用条件变量?
使用条件变量的一个条件是一个线程需要等待共享资源的某种变化才能继续执行,没用条件变量就会让线程要么一直轮询检查,浪费CPU,要么设置检查间隔,导致不实时,条件已经好了,但没去检查;所以使用条件变量加互斥锁,在不满足条件时,高效的进行等待。
条件变量的使用
条件变量的数据类型是什么?如何给条件变量进行初始化?如何销毁条件变量?条件变量的睡眠函数是睡眠是什么,需要配合哪个锁使用,上半部和下半部是什么?条件变量的时间睡眠函数是睡眠?条件变量的唤醒有哪些函数?什么是虚假唤醒,如何解决虚假唤醒?
条件变量的数据类型是 pthread_cond_t; 用 pthread_cond_init函数来对条件变量进行初始化,用 pthread_cond_destroy函数来销毁条件变量。条件变量的睡眠函数是 pthread_cond_wait函数,需要配合互斥锁使用,上部是原子地睡眠和释放锁,下半部是被唤醒然后抢锁,成功则返回(失败阻塞)。条件变量的时间睡眠函数是 pthread_cond_timewait函数。条件变量的唤醒有 pthread_cond_signal函数和 pthread_cond_broadcast函数,一个是至少唤醒一个线程另一个是全部唤醒。虚假唤醒就是当条件变量被唤醒时发现所需要的共享资源还是拿不到(例如被其他所唤醒的线程所抢走了),这就是虚假唤醒,用while循环一直判断,如果被唤醒后抢不到锁就一直循环。
其他
可以给线程设置哪些属性?如何设置线程分离?什么是线程安全?线程属性与线程安全的关系?
计算机网络
分层模型
OSI会分为哪7层?TCP/IP会分为哪4层?
OSI(物联网叔会使用)->物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。TCP分为应用层、传输层、网络层、网络接口层。
什么是协议
协议的作用是什么?每一层有哪些常见的协议?
协议是在网络通信中,双方都要遵守的规定。应用层:HTTP、FTP、SMTP、POP3、DNS、SSH、Telnet;传输层:TCP、UDP;网络层:IP、ICMP、ARP;网络接口层:以太网、WiFi、PPP。
应用层
应用层的作用是什么?有哪些常见的协议?
HTTP协议
HTTP协议是什么?特点有哪些,http1.0和http1.1的区别是什么?请求报文的组成?响应报文的组成?http与https的区别?
HTTP协议是一个超文本传输协议 ,用来进行通信双方进行传输数据所使用的协议。http特点有明文 传输,可靠 (建立在TCP的基础上的),无连接,无状态 ;http1.0 是非持续连接 ,所以每次传输完要重新建立连接,而http1.1 是持续连接 可以持续发送数据,还增加了HOTS字段和断点续传的功能等。请求报文由请求行、请求头、空行、请求体组成;请求行包括请求方法(例如GET、POST)、资源路径、协议及版本;请求头包含一些字段等。响应报文由响应行、响应头、空行、响应体组成;响应行包括协议及版本、状态码、原因短语,响应头也是一些字段。
http与https最大的区别就是https进行了加密。
传输层
TCP协议有哪些特点?TCP状态迁移图?三次握手,重要标志位,能画出过程图?四次挥手,重要标志位,过程图?TCP状态迁移图中的主动断开和被动断开有哪些常见的状态?
可以参考Linux10(计算机网络01)。
主动断开的一方最后一定有一个TIME_WAIT 时间等待状态,是2MSL;而被动断开有一个CLOSE_WAIT状态可以关注一下。
网络层
网络层的作用是什么?ip地址的作用是什么?ip地址分为哪五类?ipv4地址是多少位,ipv6地址是多少位?ip地址的头部格式是什么样的,有哪些常见字段?什么是子网掩码?网络包如果比较大如何传输?网络包在接收大包的时候如何组合?ip层使用什么硬件、该硬件有什么特点与作用?NAT的作用是什么,为何需要NAT?
网络层的作用是将上层来的数据从源主机发向目的主机,核心功能是路由选择和地址解析。ip地址的作用是唯一标识网络中的每一台设备,作用是寻址和路由,让数据包能找到正确的目标。ip地址分为A、B、C、D、E类,A类;ipv4是32位,而ipv6是128位。ip地址的头部格式的字段有版本号、首部长度、服务类型、标识、标志、片偏移、总长度、TTL、协议、源IP地址、目的IP地址、校验和。子网掩码是用于区分IP地址中的网络号和主机号的,用连续的1表示网络号,0表示主机,通过子网掩码可以判断两个IP是否在同一个局域网。网络包如果比较大就进行分片传输,拆成多个MTU(最大数据传输单元),每片都有自己的IP头部;接收端收到分片后,通过IP头的标识、偏移量、分片标志来重新组装成完整的IP包,只有全部收集齐才往上层递交,超时则丢弃。IP使用的核心硬件是路由器,特点是工作在网络层、根据路由表转发数据、隔离广播域,就是寻址和转发。NAT的作用是网络地址转换,防止IP地址的耗尽是NAT的作用,将私有IP地址转换为公网IP地址来访问互联网。
以太网
以太网作用是什么?以太网帧的格式什么?什么是DMA?
以太网的作用是封装成帧,通过物理介质在同一网络的设备之间传输数据,实现链路层通信。以太网帧的格式是(662N4,收发协数验,N是46-1500)创始人咸鱼;662N4分别对应目标MAC地址,源MAC地址,类型2字节,数据,帧校验序列,还有前导码和帧定界符7+1位。DMA是直接内存访问,是一种让硬件设备绕过CPU直接和内存读写的技术。
网络编程
网络编程基础
1.为何需要进行网络编程
因为现实世界是分布式的,大多数日常用到的软件都是基于网络编程实现的,如某音某站都是基于这个实现的。具体来收可以实现资源共享、远程服务、构建分布式系统、实时通信、综合整合外部数据等。
2.大端存储和小端存储的区别是什么
小端存储就是低字节存低位(数据的低字节存储在内存地址的低位),高字节存高位;大端相反,低字节存高位,高字节存低位。记一个小端的低字节存低位就忘不了。
3.什么是网络字节序、什么是本机字节序,本机字节序与网络字节序分别采用什么方式进行存储
网络字节序就是用大端 方式让数据在网络上传输,本机字节序大部分都是小端 ,看CPU架构,x86就是小端。
4.本机字节序如何与网络字节序进行转换
htonl函数、htons函数、ntohl函数、ntohs函数,记忆就用h = host 主机,to ,n = network , l就是长的32位,s就是short 16位。
5.什么是点分十进制ip,为何需要点分十进制ip
点分十进制就是把计算机所用的二进制,转化成我们所容易看的和写的十进制格式。
6.如何在本机的点分十进制ip与网络ip之间进行转换
6.1 涉及哪三个函数
inet_aton函数、inet_addr函数、inet_ntoa函数;详细理解可以见Linux11(网络编程)。
6.2 三个函数的传参是什么样的
inet_aton函数是本机到网络,第一个参数放点分十进制字符串,第二个参数传struct in_addr *;inet_addr传一个字符串的ip地址就行;inet_ntoa是传一个struct in_addr 的结构体。
6.3 涉及到的结构体是什么样的
涉及到的结构体struct in_addr{ in_addr_t s_addr;};
TCP和UDP的通信流程
TCP 的图可以见Linux11(网络编程)。
UDP如下图。
TCP网络通信常用函数
服务器常用函数
socket函数
这个函数的作用是什么?有几个参数,每个参数代表什么含义?函数的返回结果是什么? 底层原理是什么?
文件描述符是什么?文件描述符与文件描述符数组的关系是什么?文件描述数组中存储的是什么?什么是文件描述符对象?文件描述符与文件描述符对象之间是如何关联起来的?
作用是建立网络编程的通信端点;有三个参数;第一个参数是协议族(一般AF_INET),第二个参数是类型(SOCK_STREAM),第三个也是协议(默认0,会自动前两参数选择默认协议);底层原理是在内核创建一个对象,在这个对象中除了一些信息,还包括两个极其重要的输入缓冲区和输出缓冲区,分别用于从网络临时接收数据和发送数据。
文件描述符是内核提供给用户 用来间接访问内核的一个非负整数(但别直接用int哦),是进程内文件描述符数组的下标,内核通过这个下标找到对应的文件对象。文件描述符从用户态指向内核态 的文件描述符数组,以此来操作内核态的东西;文件描述符数组中 存储的是指向内核对象的指针;内核文件描述符所指向的文件对象为文件描述符对象;文件描述符和文件描述符对象是通过文件描述符数组来关联起来的。
bind函数
这个函数的作用是什么?有几个参数,每个参数代表什么含义?第二个参数是什么,为何不直接使用这个参数类型?这个函数中的ip与port在使用的时候是否需要转换?
这个函数的作用是为socket通信端点绑定IP和端口号;有三个参数,第一个参数是socket函数返回的文件描述符,第二个参数是一个需要强转的结构体指针(第二个参数是一个指向 struct sockaddr 类型的指针。但实际传入的通常是 struct sockaddr_in 类型的变量地址,在传参时强制转换为struct sockaddr*),第三个参数是第二个的大小。第二个参数不直接使用是因为是一个通用结构体,字段少不好进行ip和端口号的绑定。ip和port使用时需要转换,要从本机字节序转到网络字节序。
listen函数
这个函数的作用是什么?有几个参数,每个参数代表着什么?底层原理是什么?
这个的作用是来监听所设置好的socket端点的外部连接;有两个参数,第一个是socket端点的文件描述符,第二个指定了套接字可以挂起的最大连接数。底层原理就是使用半连接队列和全连接队列分别存储第一次握手和第三次握手。
accept函数
函数作用?参数?是否是阻塞函数?
accpet函数的作用是用来与客户端建立连接,然后返回文件描述符用来后续的读写(也就是从socket的全连接队列取出一个连接),参数第一个是socket端点的文件描述符,第二个参数用来存储客户端的信息(不需要可以填NULL),所得到的是网络地址,可以使用inet_ntoa来转换地址格式(格式转化,其实就是二进制IP到点分十进制字符串),端口可以用ntohs来转换(字节序转换,就是网络字节序到主机字节序);第三个参数是获取第二个结构体的大小的(第二个为NULL,第三个也要为NULL)。该函数是阻塞函数,当全连接队列为空时。
read、recv和write、send四个函数
read和write是通用的文件I/O函数,可以参考Linux03(无缓冲文件流)。
recv函数跟read的区别就是设计在网络编程通信中使用的,send与write也是同样是专门用作在网络编程中。recv和send的最后多一个标志位的参数flags,用于设置特殊的收发行为(如MSG_DONTWAIT、MSG_PEEK等),当flags等于0,效果等同于read和write。
recv和send只是将数据在用户态空间和内核态的缓冲区之间进行传输。
close函数
最后记得用close函数关闭打开的文件描述符就行。
客户端的几个函数
大部分函数跟服务器相同,如必须有socket,这里不需要bind(客户端可以绑定,也可以不绑定,用随机的临时端口)和listen函数,然后就是用connect函数,最后还是close函数关闭。建立连接就是使用connect函数使客户端向服务器发送建立连接请求,初始化一个连接,这个函数只要执行成功,说明底层已经走完了三次握手,并且第一次握手和第三次握手是这个函数走的。
客户端和服务器状态迁移图
可以查看Linux(网络编程)。
使用什么命令查看网络状态
使用netstat -apno | grep 内容,来查看网络状态。
如果服务器断开,能立马开启服务器吗
不可以立即开启服务器,因为服务器主动断开需要在TIME_WAIT中等待2MSL,可以使用setsockopt函数来解决,参数如下。

第一个参数是socket套接字的文件描述符;第二个是协议层一般填SOL_SOCKET;第三个参数是选项名称,一般填SO_REUSEPORT;第四个参数选项值指针;第五个参数选项值长度。
TCP网络编程的场景
这部分用代码说明好些。
UDP常用函数
服务器端与客户端
有socket函数、bind函数、sendto函数、recvfrom函数、close函数(跟TCP很相似)。sendto函数在send上还加入了第五个参数,就是要发送的目的地址的IP地址和端口号,这是一个结构体,而第六个参数是第五个参数的结构体长度;recvfrom也是类似的第五个参数是存发送方的地址信息,第六个参数是第五个参数的结构体大小。这是因为没有建立连接,所以必须总是由客户端先发送sendto给服务端;而由于是无连接,所以客户端或服务器关闭,对方无法知道。
I/O多路复用
select函数
如下图,第一个参数是最大文件描述符的个数加1;第二到四,分别是读、写、异常的位图集合;第五个参数就是时间,要等待的时间上限,一直等待就填NULL。函数的返回结果就是就绪文件描述符的个数,而第二到四所要定义的一个位图,要用到FD_CLR函数,将某一fd从位图中置0、FD_ISSET函数,检测fd是不是还在set中、FD_SET函数,将fd添加到位图中进行监听,也就是置1、FD_ZERO函数,清空位图,全部置0。
底层原理 :先fd_set set声明个位图,然后用FD_SET/FD_ZERO初始化位图,也就是在用户态创建对应的读或写或异常的位图(想创哪个创哪个,大多用读事件),然后用select函数把位图拷到内核态中,内核态遍历fd,然后进行修改(也就是有就绪的文件描述符就依旧设置为1,没有就修改为0),又拷回到用户态,所以内核态经过了什么修改,在用户看来是不知道的,也就需要用上面的FD_ISSET函数来查看了。

epoll
为何要用epoll,epoll有什么特点(优缺点等)?epoll的底层原理?epoll所使用的函数?epoll的两种触发模式?
为了解决select的文件描述符的上限1024 和频繁在内核态与用户态切换 、以及监听和就绪的位图是同一个 的缺点,所以采用了一种更高效的I/O多路复用技术epoll,缺点是epoll是在Linux
下使用的,跨平台select有优势(但其他平台也有和epoll类似的机制)。
epoll的底层原理是通过epoll_create在内核态创建包含红黑树 和双向链表 (就绪集合)的文件对象(内核的文件描述符数组会指向这个创建的文件对象),红黑树用来监听 (类似与select函数的底层原理的监听),监听到有就绪的文件描述符就先拷到内核的就绪集合(也就是拷到双向链表),然后通过epoll_wait函数来将就绪集合(也就是双向链表中的就绪好的文件描述符)拷贝到用户态里的就绪集合。
epoll主要有epoll_create()、epoll_ctl()、epoll_wait() 三个函数,使用epoll_create函数来创建、使用epoll_ctl函数来将文件描述符放到红黑树上监听或取消监听,如果是监听还可以监听文件描述符对应的读写事件、最后用epoll_wait将就绪的结果拷到用户态。
epoll函数主要有两种触发模式,一种水平触发(LT) ,一种边缘触发(ET),水平触发是epoll默认的工作模式,在这种模式下,只要有待处理的事件,epoll_wait就会通知应用程序进行处理;而边缘触发只在文件描述符状态发生变化时,通知应用程序(即可不可以用,程序结果出不出来)。