文章目录
1、三次握手四次挥手全过程
前提须知:
TCP的传送单元称为报文段。一个TCP报文段又分为TCP首部和TCP数据两部分。整个TCP报文段都封装在IP的数据报中数据部分。TCP首部的长度是4的倍数,并且有20个固定的字节,剩余的就是可变动的选项与填充。最常见的可选字段是 最大报文大小又称MSS 。20个固定的字节包括 源端口号(2字节),目的端口号(2字节),seq序列号(4),确认号ack(4字节)以及确认为ACK等
首先在三次握手建立连接的过程中,是不会传输TCP报文段的。传输的是 传输控制块 TCB(Transmission Controller Block),tcb存储了每一个连接中的一些重要信息,如:TCP连接表,指向发送和接收缓存的指针,指向重传队列的指针,当前的发送和接收序号等。
三次握手过程:
1、首先客户端与服务端都是处于CLOSED的状态,由于服务端不知道要跟谁建立连接,所以只能被动打开,然后监听端口。此时Server处于Listen状态
2、而Client端会主动打开,并且构建TCB块[SYN = 1 , seq = x]发送给服务端,此时客户端状态为SYN_SENT
3、服务端在接收到客户端发来的同步请求后,会将状态置为 SYN_RECV,并且会构建TCB [SYN = 1, ACK = 1,seq = y ,ack = x+1]发送给客户端
4、客户端在接收到服务端发来的数据之后,会将状态置为ESTABLISHED 【建立连接】,然后发送确认报文(ACK = 1,seq =x+1,ack = y+1)
5、服务端在接收到客户端发来的报文后,也将状态置为ESTABLISHED,此时三次握手就已经结束了。在第三次传输时,可以将TCP报文段信息一起发送,因为此时已经保证了连接是可靠的。
为什么不能是两次握手?
分析一个问题:如果第一个请求发送给服务端时,因为网络堵塞,此时没有及时传输到。又因为客户端超时校验,所以会重新发送,然后传输结束,然后关闭传输。 在此之后,网络突然好了,第一个请求到达了服务端,此时因为只有两次握手,然后又建立了连接。这将导致不必要的错误和资源的浪费。
四次挥手过程:
1、最开始客户端与服务端都处于ESTABLISHED状态,然后客户端会主动关闭,服务端则是被动关闭
2、客户端首先会发送一个FIN(结束)报文段。构建TCB [ FIN = 1,seq = u (u代表要结束的报文段序号+1)],告诉服务端,客户端要断开连接了。此时客户端的状态置为FIN-WAIT-1
3、服务端在接收到客户端发送来的结束FIN报文段后,会发送一个ack报文给客户端,其中报文为ACK = 1,seq = v,ack = u + 1.此时服务端会通知应用进程需要关闭连接了,并将自己的状态置为CLOSE-WAIT;
4、客户端在收到响应包后将状态置为FIN-WAIT-2
5、由于服务端可能还有一些数据没有处理,所以需要等待一段时间再次发送,等到处理完后,再次发送一条报文,其中FIN = 1,ACK=1,seq = w ,ack = u+1。告知客户端此时我可以结束了。并且将状态置为LAST-ACK
6、客户端在收到服务端发来的消息后,会再次发送一个ack报文回去 其中ACK = 1,seq = u+1,ack = w+1.告知服务端,客户端已经知道你准备好了,此时客户端会将状态更改为TIME-WAIT,在两个最长报文段传输时间过后,会自动将客户端的状态由TIME-WAIT变更为CLOSED;
7、服务端再接收到客户端传来的ack报文后,也会将状态更改为CLOSED。至此,四次挥手过程结束。
为什么不能是三次挥手?
如果取消最后一次挥手,那么服务端可能在第二次确认中,数据丢失了,但是却不知道,客户端一直在等待重传,服务端则直接关闭了。
如果合并中间两次挥手,那么服务端可能还没有传输完数据,此时关闭一定会产生异常。
为什么要等待2个最长报文端传输时间?
防止最后自己发去的ack没传送到服务器。那么服务器会再重发一次FIN包,这样客户端能够再次发送一个确认。一来一回刚好是2哥最长报文传输时间。
2、排序算法分为哪些?
-
比较排序
- 交换排序
- 冒泡 时间O(n2) 空间O(1) 稳定
- 快排 时间O(nlogn) 空间O(logn) 不稳定
- 选择排序
- 简单选择排序 时间O(n2) 空间O(1) 不稳定
- 堆排序 时间O(nlogn) 空间O(1) 不稳定
- 插入排序
- 直接插入排序 时间O(n2) 空间O(1) 稳定
- 希尔排序 时间O(n1.3) 空间O(1) 不稳定 最好n最快n2
- 归并排序
- 二路归并 时间O(nlogn) 空间O(n) 稳定
- 多路归并
- 交换排序
-
非比较排序
- 计数排序 时间O(n+k) 空间O(n+k) 稳定
- 桶排序 时间O(n+k) 空间O(n+k) 稳定
- 基数排序 时间O(n*k) 空间O(n) 稳定
不稳定:快希选堆
3、索引的简历原则有哪些
最左前缀,索引下推,考虑索引长度。
4、select,poll,epoll模型
(3)select模型:对于上述的非阻塞忙轮询IO模型的CPU空转的缺点进行补充。
在所有流都不可读取和写入的时候,CPU会空转,那么引入一个select代理,用于检测所有流是否可读取和可写入,如果所有流都不可读取和写入,那么这个线程将阻塞,如果至少有一个流可读取或写入,那么就会将阻塞的线程唤醒。其实select模型下,维护一个fd_set数据结构(使用的是Bitmap位图算法),每一个元素与流关联,每次调用select()方法时,需要将这个数据结构拷贝到内核态,然后内核判断哪些流可读或可写,并写入到这个数据结构然后拷贝到用户态。因此 1.如果数据结构太大,在用户态和内核态之间拷贝会很耗性能;2.在内核态中,每次都要遍历这个数据结构的所有元素,比较耗性能;3.为了减少拷贝对性能的损害,内核对这个集合的大小做了限制(1024,大小不可修改);
(4)poll模型:这个模型跟select模型类似,只是没有对fd_set数据结构集合的大小做限制,因此只解决了select模型的第三个缺点,第一、二个缺点依然存在;
(5)epoll模型:该模型基于事件驱动的方式,使用一个文件描述符来管理多个描述符,描述符的数量没有限制。每当fd就绪,就会调用系统注册的回调函数,将fd加入到readyList中。进行IO操作的时候,只需要遍历这个readyList,而不需要遍历所有的fd。因此解决了CPU空转、遍历所有fd、大集合在用户态和内核态之间拷贝的性能消耗的缺点。
epoll是Linux目前大规模网络并发程序开发的首选模型。在绝大多数情况下性能远超select和poll。目前流行的高性能web服务器Nginx正式依赖于epoll提供的高效网络套接字轮询服务。但是,在并发连接不高的情况下,多线程+阻塞I/O方式可能性能更好。
5、解决跨域问题
https://www.cnblogs.com/zyndev/p/13697313.html#%E4%BB%80%E4%B9%88%E6%98%AF%E8%B7%A8%E5%9F%9Fcors
6、线程、进程、协程
线程是系统调度执行的最小单位
进程是资源分配的最小单位
一个进程可能有多个线程,最少有一个,但是一个线程只能属于一个进程。
协程,是一种比线程更加轻量级的存在,协程不是被操作系统内核所管理,而完全是由程序所控制(也就是在用户态执行)。这样带来的好处就是性能得到了很大的提升,不会像线程切换那样消耗资源。
优点:无需从内核态切换到用户态,减少内存消耗,极大的提升效率
因为协程只有一个线程,所以不存在写冲突,所以不需要加锁,提高效率
7、Cookie与Session的区别
cookie和session都是用来跟踪浏览器用户身份的会话方式。
存放位置不同 cookie存放在客户端,session存放在服务端
cookie不是很安全,可能本地篡改cookie,尽量使用session
单个cookie在客户端的限制是3K
8、HTTP报文
HTTP使用统一资源定位符(URL):协议:// 主机:端口 / 路径
HTTP请求报文
1、请求行
GET:当客户端要从服务器中读取某个资源时,使用GET 方法。GET 方法要求服务器将URL 定位的资源放在响应报文的部分,回送给客户端,即向服务器请求某个资源。使用GET 方法时,请求参数和对应的值附加在 URL 后面,利用一个问号(“?”)代表URL 的结尾与请求参数的开始,传递参数长度受限制。例如,/index.jsp?id=100&op=bind。
POST:当客户端给服务器提供信息较多时可以使用POST 方法,POST 方法向服务器提交数据,比如完成表单数据的提交,将数据提交给服务器处理。GET 一般用于获取/查询资源信息,POST 会附带用户数据,一般用于更新资源信息。POST 方法将请求参数封装在HTTP 请求数据中,以名称/值的形式出现,可以传输大量数据;
2、请求头部
User-Agent:产生请求的浏览器类型;标志客户端程序
Accept:客户端可识别的响应内容类型列表;星号 “ * ” 用于按范围将类型分组,用 “ / ” 指示可接受全部类型,用“ type/* ”指示可接受 type 类型的所有子类型;
Accept-encoding
Accept-Language
referer
Host:请求的主机名,允许多个域名同处一个IP 地址,即虚拟主机;
connection:连接方式(close 或 keepalive);
Cookie:存储于客户端扩展字段,向同一域名的服务端发送属于该域的cookie;
3、请求包体
请求时携带的数据
HTTP响应报文
1、状态行
1xx Informational(信息性状态码) 接受的请求正在处理
2xx Success(成功状态码) 请求正常处理完毕
3xx Redirection(重定向) 需要进行附加操作以完成请求
4xx Client error(客户端错误) 客户端请求出错,服务器无法处理请求
5xx Server Error(服务器错误) 服务器处理请求出错
数字中的第一位指定了响应类别,后两位无分类,响应类别有一下5种:
200 OK:表示客户端请求成功;
301: Moved Permanently 永久重定向,浏览器会保存记录
302:**Found:**临时性重定向
400 Bad Request:表示请求报文中存在语法错误;
401 Unauthorized:未经许可,需要通过HTTP认证;
403 Forbidden:服务器拒绝该次访问(访问权限出现问题)
404 Not Found:表示服务器上无法找到请求的资源,除此之外,也可以在服务器拒绝请求但不想给拒绝原因时使用;
500 Inter Server Error:表示服务器在执行请求时发生了错误,也有可能是web应用存在的bug或某些临时的错误时;
503 Server Unavailable:表示服务器暂时处于超负载或正在进行停机维护,无法处理请求;
Access-Control-Allow-Headers:
Connection
Content-Length
Content-Type
3、响应体
9、HTTP与HTTPS的区别
1、HTTPS 协议需要到 CA (Certificate Authority,证书颁发机构)申请证书,一般免费证书较少,因而需要一定费用。(以前的网易官网是http,而网易邮箱是 https 。)
2、HTTP 是超文本传输协议,信息是明文传输,HTTPS 则是具有安全性的 SSL 加密传输协议。
3、HTTP 和 HTTPS 使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
4、HTTP 的连接很简单,是无状态的。HTTPS 协议是由 SSL+HTTP 协议构建的可进行加密传输、身份认证的网络协议,比 HTTP 协议安全。(无状态的意思是其数据包的发送、传输和接收都是相互独立的。无连接的意思是指通信双方都不长久的维持对方的任何信息。)
10、HTTPS的工作流程
1、客户端发送HTTPS请求向服务端的443端口,并且携带加密方式等信息
2、服务端收到请求后,确认双方的加密方式,然后将自己的证书,加密方式发给客户端
3、客户端收到证书后,再本地通过TLS验证,去操作系统的CA证书里查找信息,如果发现信息一致的话,就说明这个证书没问题,取出证书的公钥。并且随机生成一个随机数
4、用公钥加密这个随机数(也就是私钥)在发送给服务端
5、服务端接收到这个数后,通过用服务端的私钥进行解密,也就得到了客户端生成的随机数(客户端的私钥)。然后将要传输的数据通过该随机数进行对称加密。
6、将数据传输给客户端
7、客户端通过私钥解密
https://zhuanlan.zhihu.com/p/96494976
HTTPS 在内容传输的加密上使用的是对称加密,非对称加密只作用在证书验证阶段。
HTTP 1.0与HTTP 1.1与HTTP 2.0的区别
HTTP1.0和HTTP1.1的一些区别
HTTP1.0最早在网页中使用是在1996年,那个时候只是使用一些较为简单的网页上和网络请求上,而HTTP1.1则在1999年才开始广泛应用于现在的各大浏览器网络请求中,同时HTTP1.1也是当前使用最为广泛的HTTP协议。 主要区别主要体现在:
- 缓存处理,在HTTP1.0中主要使用header里的If-Modified-Since,Expires来做为缓存判断的标准,HTTP1.1则引入了更多的缓存控制策略例如Entity tag,If-Unmodified-Since, If-Match, If-None-Match等更多可供选择的缓存头来控制缓存策略。
- 带宽优化及网络连接的使用,HTTP1.0中,存在一些浪费带宽的现象,例如客户端只是需要某个对象的一部分,而服务器却将整个对象送过来了,并且不支持断点续传功能,HTTP1.1则在请求头引入了range头域,它允许只请求资源的某个部分,即返回码是206(Partial Content),这样就方便了开发者自由的选择以便于充分利用带宽和连接。
- 错误通知的管理,在HTTP1.1中新增了24个错误状态响应码,如409(Conflict)表示请求的资源与资源的当前状态发生冲突;410(Gone)表示服务器上的某个资源被永久性的删除。
- Host头处理,在HTTP1.0中认为每台服务器都绑定一个唯一的IP地址,因此,请求消息中的URL并没有传递主机名(hostname)。但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机(Multi-homed Web Servers),并且它们共享一个IP地址。HTTP1.1的请求消息和响应消息都应支持Host头域,且请求消息中如果没有Host头域会报告一个错误(400 Bad Request)。
- 长连接,HTTP 1.1支持长连接(PersistentConnection)和请求的流水线(Pipelining)处理,在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟,在HTTP1.1中默认开启Connection: keep-alive,一定程度上弥补了HTTP1.0每次请求都要创建连接的缺点。
HTTP2.0和HTTP1.X相比的新特性
- 新的二进制格式(Binary Format),HTTP1.x的解析是基于文本。基于文本协议的格式解析存在天然缺陷,文本的表现形式有多样性,要做到健壮性考虑的场景必然很多,二进制则不同,只认0和1的组合。基于这种考虑HTTP2.0的协议解析决定采用二进制格式,实现方便且健壮。
- 多路复用(MultiPlexing),即连接共享,即每一个request都是是用作连接共享机制的。一个request对应一个id,这样一个连接上可以有多个request,每个连接的request可以随机的混杂在一起,接收方可以根据request的 id将request再归属到各自不同的服务端请求里面。
- header压缩,如上文中所言,对前面提到过HTTP1.x的header带有大量信息,而且每次都要重复发送,HTTP2.0使用encoder来减少需要传输的header大小,通讯双方各自cache一份header fields表,既避免了重复header的传输,又减小了需要传输的大小。
- 服务端推送(server push),同SPDY一样,HTTP2.0也具有server push功能。
11、Mysql如何优化
1、生产环境尽量避免使用子查询
2、避免函数索引
3、用IN来替换OR
4、LIKE前缀%号、双百分号、_下划线查询非索引列或*无法使用到索引,如果查询的是索引列则可以
5、读取适当的记录LIMIT M,N,而不要读多余的记录
如果数据过多时,还可以添加上限制条件
select id,name from table_name where id> 866612 limit 20
6、禁止不必要的ORDER BY排序
7、批量INSERT插入
8、尽量不用select *
12、避免索引失效
1、最佳左前缀法则
如果索引了多列,要遵守最左前缀法则,指的是查询从索引的最左前列开始并且不跳过索引中的列
2、不在索引列上做任何操作
3、存储引擎不能使用索引中范围条件右边的列
如这样的sql: select * from user where username=‘123’ and age>20 and phone=‘1390012345’,其中username, age, phone都有索引,只有username和age会生效,phone的索引没有用到。
4.尽量使用覆盖索引(只访问索引的查询(索引列和查询列一致))
如select age from user减少select *
5、如果使用!=或者<>会导致索引失效
6、is null, is not null 也无法使用索引,在实际中尽量不要使用null。
7、like 以通配符开头(‘%abc…’)mysql索引失效会变成全表扫描的操作。
8、字符串不加单引号索引失效
9、少用or,用它来连接时会索引失效
13、联合索引优化
全值匹配:指和索引中的所有列进行匹配,例如查找name=‘Jone’ and age=13 and sex='男’的人;
匹配最左前缀:指用索引的第一列name,如where name=‘Jone’,该查询只使用了索引的第一列
匹配列前缀:匹配索引列值的开头,如where name like ‘J%’,查找名字以J开头的人;
匹配范围值:例如查找年龄在10-30之间的Jone,where name=‘Jone’ and age between 10 and 30;
如果不是按照索引的最左列进行查找,则无法使用索引,如当仅查找表A中年龄为15岁的人时则无法使用索引;
不能跳过索引中的列,如查找表A中名字为Jone且为男性的人,则索引只能使用name列,无法使用sex列;
查询中索引的某列是范围查询,则该列后的查询条件将不能使用索引。
14、nginx使用
在nginx的conf.d 中新建一个配置 然后在server中修改要监控的server_name 并且新增location
在nginx.conf中 添加上要转发的网关
Nginx动静分离
15、Java性能调优
一般使用Jmeter来测试接口,通过自带的多线程请求,能够看到 汇总分析 (最大连接时间,最小连接时间,异常数等)可以有效的进行调优测试
java -Xmx3550m -Xms3550m -Xmn2g -Xss128k
**-Xmx3550m:设置JVM最大可用内存为3550M。
-Xms3550m:设置JVM促使内存为3550m。此值可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存。
-Xmn2g:设置年轻代大小为2G。整个JVM内存大小=年轻代大小 + 年老代大小 + 持久代大小。持久代一般固定大小为64m,所以增大年轻代后,将会减小年老代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8。
-Xss128k:设置每个线程的堆栈大小。JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K。更具应用的线程所需内存大小进行调整。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右。
性能调优 与 数据库,应用程序、中间件(tomcat,nginx) 网络与操作系统
考虑自己属于CPU密集型(大量运行) 还是 IO密集型(大量吞吐)
垃圾回收也就是回收的堆内存(新生代,老年代)
java调优工具
jconsole
jvisualvm(推荐)
先单独每哥中间部分测试,然后在合起来测 比较性能
16、Redis为什么这么快
1、首先因为redis是存储在内存中的,速度很快
2、因为redis在处理网络请求的时候是单线程的,减少了线程上下文切换,以及并发处理等操作,所以速度很快
3、因为采用了多路复用io阻塞机制
17、Redis 持久化
RDB
RDB持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘,实际操作过程是fork一个子进程,先将数据集写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储。
https://www.cnblogs.com/zhenghongxin/p/8669913.html
1 执行bgsave命令(此时redis会fork一个子进程,子进程负责生成硬盘文件,父进程负责继续接受命令)
2 或执行save命令(和bgsave命令不同,发送save命令后,到系统创建快照完成之前系统不会再接收新的命令,换句话说save命令会阻塞后面的命令,而bgsave不会)
3 用户在配置文件了配置了类似这样的命令
save 900 1 // 900内,有1条写入,则产生快照
save 300 1000 // 如果300秒内有1000次写入,则产生快照
save 60 10000 // 如果60秒内有10000次写入,则产生快照
(这3个选项都屏蔽,则rdb禁用)
4 用户发送shutdown,系统会先导员save命令阻塞客户端,然后关闭服务器
5 当有主从架构时,从服务器向主服务器发送sync命令来执行复制操作时,只有主服务器当时没有进行bgsave操作,那么主服务器就会执行bgsave操作。
AOF
AOF持久化以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,以文本的方式记录,可以打开文件看到详细的操作记录。