实习笔记五—-实习前准备面试的一些知识点,由于没有在面试中被考察到,因此上篇博客没有记入,这里做一些总结
网络
知识点:tcp/ip(握手挥手、各个信号意义、超时重传、滑动窗口、拥塞控制、流量控制)、http/https(长连接短连接、头压缩、服务端推送、二进制传输、各个请求类型、各种状态码、幂等、网络攻击)、tcp/udp,七层模型,五层模型,四层模型
TCP三次握手与四次挥手
三次握手的过程
- 建立连接时,客户端发送SYN包(syn=j)到服务器,并进入SYN-SEND状态,等待服务器确认
- 服务器收到SYN包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACk包,此时服务器进入SYN-RECV状态
- 客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端与服务器进入ESTABLISHED状态,完成了三次握手
三次握手用于防止“已失效的连接请求报文段”。
四次挥手
- 主动关闭方发送一个FIN,告诉被动关闭方,我已经不再给你发送数据了(在FIN包之前发送的数据,如果没有收到对应的ACK确认报文,主动关闭方依然会重发送这些数据)
- 被动关闭方收到FIN包后,发送一个ACK给对方,确认序列号为收到序号+1,与SYN相同,一个FIN占用一个序号
- 被动关闭方发送一个FIN,用来关闭被动关闭方到主动关闭方的数据传送,告诉主动方,我的数据也发送完了,不会再给你发数据了
- 主动关闭方收到FIN后,发送一个ACK给被动关闭方,确认序号为收到序号+1
四次挥手过程中,谁主动断开,谁有time_wait,被断开一方有close_wait
- SYN:建立一个新连接
- FIN:释放一个连接
- RST:重置连接
为什么是三次握手,四次挥手:在握手时服务端在listen状态,收到建立连接的syn报文后,将ack和syn放在一个报文发送给对方,而关闭连接时,收到对方的FIN报文时,仅仅表示对方不再发送数据了但还能接收数据,己方也未必全部数据都发送给了对方,所以己方可以立即close,也可以发送一些数据给对方后再发送FIN报文给对方表示同意现在关闭连接,因此己方ACK和FIN一半都会分开发送
未连接队列
在3次握手协议中,服务器维护一个未连接队列,该队列为每个客户端的SYN包(syn=j)开设一个条目,该条目表明服务器已收到SYN包,并向客户端发出确认,正在等待客户端的确认包。这些条目所标识的连接数在服务器处于SYN_RECV状态,当服务器收到客户端的确认包时,则删除该条目,服务器进入ESTABLISHED状态。
Backlog参数:表示未连接队列的最大容纳数目。
SYN-ACK重传次数:服务器发送完SYN-ACK包,如果未收到客户端确认包,服务器进行首次重传,等待一段时间仍未收到客户确认包,进行第二次重传,如果重传次数超过系统规定的最大重传次数,系统将该连接信息从半连接队列中删除。注:每次重传等待的时间不一定相同。
半连接存活时间:也称为timeout时间、SYN-RECV存活时间。
浏览器打开网页中间发生的过程
DNS解析,查IP,应用层客户端发送HTTP请求,决定是UDP还是HTTP传输,数据进入网路层通过SPF或者BGP查找下一跳主机,找到下一条主机后用ARP协议解析得到MAC地址,进入数据链路层,数据传输,服务器接收数据,服务器响应数据,页面渲染DOM树
- HTTP请求总共有八种: get(幂等), post(不幂等), head(幂等), put(幂等), delete(幂等), connect, options, trace
- OSI参考模型有7层:物理层,数据链路层,网络层,传输层,会话层,表示层,应用层
- TCP/IP五层:应用层,传输层,数据链路层,物理层
- TCP/IP四层:应用层,传输层,网络层,网络接口层
OSI七层
- 应用层:文件传输,电子邮件,HTTP, FTP, SMTP, DNS, Telnet
- 表示层
- 会话层
- 传输层:提供端对端的接口,TCP,UDP
- 网络层:为数据包选择路由:IP, ICMP, RIP, OSPF, BGP, IGMP
- 数据链路层
- 物理层:以二进制在物理媒体上传输数据,ISO2110, IEEE802
长短连接
短连接:客户端与服务器每进行一次HTTP操作,就建立一次连接,任务结束就中断
长连接:网页打开后,TCP连接不会关闭,客户端再次访问这个服务器会继续使用这一条已建立的连接。keep-alive不会永久保持连接,有一个保持时间。实现长连接需要服务器和客户端都支持。
客户端不希望长连接:header: connection : close 服务端不希望长连接:response: connection : close
keep-alive状态下如何知道内容是否发送完毕:
- content-length
- chunk会包含body结束的标志
TCP拥塞控制过程
慢启动,拥塞避免,快速重传,快速恢复
拥塞控制的算法:慢开始算法、拥塞避免算法、快重传算法、快恢复算法
流量控制
如果发送者发送数据过快,接收者来不及接收,那么就会有分组丢失。为了避免分组丢失,控制发送者的发送速度,使得接收者来得及接收,这就是流量控制。流量控制的根本目的是防止分组丢失,它是构成TCP可靠性的一方面。
实现流量控制:由滑动窗口协议(连续ARP协议)实现。滑动窗口协议既保证了分组无差错,也实现了流量控制。主要的方式就是接收方返回的ACK中会包含自己的接收窗口大小,并且利用大小来控制发送方的数据发送。
拥塞控制是作用于网络的,避免网络负载过大的情况。流量控制是作用于接收者的,它是控制发送者的发送速度从而使接收者来得及接收,防止分组丢失的。
HTTP
- HTTP/1.1: 长连接(默认),节约带宽,HOST域,管道机制,分块传输编码
- HTTP/2: 多路复用,服务器推送,头信息压缩,二进制协议等
- HTTPS: SSL/TLS建立全信道,加密数据包。内容加密+验证身份+保护数据完整性
操作系统
知识点:进程线程协程,进程通信,并发并行,虚拟内存,进程调度,锁, Linux, IO复用,链接库,程序运行过程,调用约定
- Linux的几种io: aio, bio, nio
- 内存调度方式有:分页式、段式、段页式
- 调度算法:先来先服务、短作业优先、高优先权优先、时间片轮转、多级反馈队列
- 调度时机:进程执行完毕、阻塞、自己的时间片用完、发生中断
- 进程与线程的区别:进程是程序的一次执行。线程可以理解为进程中执行的一段程序片段。进程间是独立的,这表现在内存空间、上下文环境上;线程运行在进程空间。一般来讲,不适用特殊技术,进程无法突破进程边界存取其他进程内的存储空间;而线程由于处于进程空间内,所以同一进程所产生的的线程共享同一内存空间。
- 线程同步的方法:临界区,互斥量,信号量,事件
linux下的命令
- 查看CPU:
lscpu
- 查看内存:
free
- 查看磁盘:
dfoth
- 查看IO:
iostat
- 查看进程:
ps, top, pgrep, pstree
IPC
进程间的通信包括:信号量,信号,消息队列,共享内存等方式。unix下可以建立UNIX_DOMAIN的socket,windows可以通过IOCP建立给予命名管道的IPC,此外Mac系统还有Mach port端口可用于进程间通讯。
- 管道:剧透亲缘关系之间的进程间通信,父子进程(只能单向流动)
- FIFO命名管道:文件,适用于任何进程,但速度慢
- 信号量:不能传递复杂消息,仅能用于同步
- 消息队列:可以实现消息的随机查询,容量受到系统限制
- 共享内存最快
比如,在Mac下的ipc的设计可以是这样:
使用Unix下的本地套接字AF_UNIX建立通信。使用 AF_UNIX 会在系统上创建一个 socket 文件,不同进程通过读写这个文件来实现通信。type可以选择 SOCK_DGRAM 或 SOCK_STREAM。使用SOCK_STREAM 意味着会提供按顺序的、可靠、双向、面向连接的比特流。SOCK_DGRAM 意味着会提供定长的、不可靠、无连接的通信。
UNIX domain socket 与网络 socket 编程最明显的不同在于地址格式不同,用结构体 sockaddr_un
表示,网络编程的 socket 地址是 IP 地址加端口号,而 UNIX domain socket 的地址是一个 socket 类型的文件在文件系统中的路径,这个 socket 文件由 bind()
调用创建,如果调用 bind()
时该文件已存在,则 bind()
错误返回。因此,一般在调用 bind()
前会检查 socket 文件是否存在,如果存在就删除掉。
struct sockaddr_un {
sa_family_t sun_family; /* AF_UNIX */
char sun_path[108]; /* Pathname */
};
网络 socket
编程类似,在 bind
之后要 listen
,表示通过 bind
的地址(也就是 socket 文件)提供服务。
接下来必须用 accept()
函数初始化连接。accept()
为每个连接创立新的套接字并从监听队列中移除这个连接。
在绑定、监听了套接字之后,为了实现io复用(多个IO复用一个线程处理,节约线程,内存),使用kqueue进行调度。在服务器运行的过程中,对kqueue进行轮询,在所有的kevent中查找就绪的io事件(最多支持32个fd),并根据就绪的事件的类型分别进行处理,例如读,写,建立新的连接或者关闭连接。
ServerImpl的初始化流程如下:
- 创建AF_UNIX的socket,得到fd
- 删除指定路径下已经存在的文件
- 为地址结构体设置路径
- 绑定地址结构体与socket的fd
- 调用
listen
方法监听fd - 调用kqueue实现io复用
服务器的接口包括Listen
, CloseChannel
, Shutdown
.listen
函数会传进去一个回调函数,在新的socket连接建立时会调用此回调函数,服务器将在新的线程中轮询,不阻塞主线程。
ChannelImpl
是与ServerImpl
类强相关的,构造函数需要传入fd
和ServerImpl
的共享指针。各个fd对应一个Channel,用于消息的读,写,解析,连接的关闭,并执行消息的读、写、关闭的回调函数。
ChannelImpl
的初始化对fd对应的文件设置为非阻塞的。写消息时,每一条消息均为一行,存储到缓冲区当中,当执行OnReadyToWrite
函数时,会将缓冲区中的字符写入到fd中。
Windows可以调用 CreateIoCompletionPort
函数,将创建一个IOCP的句柄。IOCP是支持多个同时发生的异步I/O操作的应用程序编程接口。
参见:
- http://man7.org/linux/man-pages/man7/unix.7.html
- https://www.cnblogs.com/sparkdev/p/8359028.html
- https://blog.csdn.net/zdy0_2004/article/details/51805744
- https://www.jianshu.com/p/64aee4e7023c
- https://www.xuebuyuan.com/774780.html
C++
语言关键字
mutable
关键字:可变的final
关键字:不希望被继承或不希望被override
C++11新特性
lambda表达式,随机数,template双«»,nullptr,智能指针,散列容器,std::array, chrono, auto, std::thread, 基于范围的for循环,完美转发和移动语义,std::function
C++11新特性
特殊函数(数学),filesystem
数据库
知识点:ACID,隔离级别,常用语句,锁,B树/B+树,磁盘操作,存储引擎,主从复制,读写分离,关系型/非关系型,事务/非事务,组合索引,二级索引,范式
ACID
- 原子性:要么执行,要么不执行,不会执行一半停滞
- 一致性:约束
- 独立性:两个以上的事务不会交错执行,因为这样可能导致数据不一致
- 持久性:事务运行完成后,更新是永久的,不会无缘无故的回滚
redis数据结构
字符串,列表,map,set,有序集
主从复制的作用
数据冗余,故障恢复,负载均衡,读写分离,高可用基石
数据库的隔离级别
-
- 读未提交,可以读到事务未提交的数据,脏读
-
- 读提交,解决脏读问题,只能读到事务已提交的数据,但不可重复读
-
- 可重复读,解决不可重复读的问题,可能会丢失更新
-
- 序列化,事务串行执行
算法
知识点:二叉树、BST、链表、栈、红黑树、散列表、AVL树、字典树、动态规划、二分查找、递归、(堆排序、快排、归并、希尔、桶排序)、复杂度稳定性
- 哈希碰撞的解决办法:开放地址法,链地址法
- 二叉树遍历原则:前序根左右,中序左根右,后序左右根
- 读写锁适合于对于数据结构的读次数比写次数多得多的情况
- 复杂度为O(nlog(n))的排序算法:快排、归并排序、堆排序
其他
- Node.js是一个事件驱动I/O服务端JavaScript环境,基于谷歌的V8引擎。libuv库处理网络,访问文件系统等。
消息队列的应用场景
- 异步处理
- 应用耦合
- 限流削峰(相当于消息队列做了一次缓冲)
C++消息队列:ZeroMQ(不是绝对意义上的消息队列)
ZMQ是一个简单好用的传输层,像框架一样的socket-library. socket是一对一,而ZMQ实现了N: M. 包括了回应模式(1对N),发布订阅模式(单向1对N),还有推拉模式。
高并发技术方案
- 分布式缓存,结合CDN
- 消息队列作为中间件,解决大量消息的异步处理能力
- 应用拆分
- 数据库垂直拆分与水平拆分
- 数据库读写分离
- 限流机制