Http

4 minute read

http协议属于应用层协议,传输层使用tcp协议,网络层使用ip协议。

ip协议解决网络路由、寻址问题,tcp协议解决如何在ip层之上可靠地传递数据包,使在网络的另一端收到发端发出的所有包,并且顺序与发出顺序一致,tcp有可靠、面向连接的特点。

http是无状态的,指的是协议对于事务处理没有记忆能力,举例来说打开一个网页和之前打开这个网页之间没关系。

http是一个无状态的面向连接的协议,无状态不代表http不能保持tcp连接,更不能代表http使用的是udp协议。

http/1.0默认使用短连接,短连接是指每一次客户端和服务端的交互,就建立一次连接,交互结束,连接就会中断。 http/1.1默认使用长连接,用以保持连接特性。使用长连接的http协议,会在响应头加入这行配置。 Connection:keep-alive 在使用长连接的情况下,当一个网页打开完成后,客户端和服务器之间用于传输http数据的tcp连接不会关闭,如果客户端再次访问这个服务器上的网页,会继续使用这一条 已经建立的连接。keep-alive不会永久保持连接,会有一个保持时间。实现长连接需要客户端和服务端都支持。

tcp短连接 client向server发起连接请求,server接到请求,双方建立连接。client向server发送消息,server回应client,一次读写就完成了。这时候双方任何一个都 可以发起close操作,不过一般都是由client发起close请求。一般server不会回复完client立即关闭连接,也就是说短连接一般只会在client/server传递一次读写操作。

短连接优点:管理简单,存在的连接都是有效连接,不需要额外控制手段

tcp长连接 client向server发起连接请求,双方建立连接。client与server完成一次读写之后,连接不会被主动关闭,后续的读写操作会继续使用这个连接。 tcp保活功能,保活功能主要为服务器应用提供,在服务器端检测这种半开放的连接,如果客户端已经消失,将关闭这种连接。

长连接可以省去频繁建立和关闭连接的操作,对于频繁请求的客户端,适合长连接,不过长连接的一个问题是保活探测太长,随着客户端连接越来越多,服务端压力会越来越大, 甚至恶意连接。解决这个问题需要服务端采取一些策略,如关闭一些长时间没有读写时间的连接、以客户端ip为维度限制连接数量

长连接多用于操作频繁、点对点的通讯,而且连接数不能太多,例如数据库的连接

短连接适合并发量大、每个客户端无需频繁操作的场景,web网站的http服务一般使用短连接,因为成千上万的客户端如果用长连接,服务端扛不住这么大的连接量。

长短连接有什么优缺点呢? 长连接:一直保持连接,复用连接,连接池用的就是长连接。比如说我们常用的数据库连接池,TCP连接就是长连接。 长连接的优点就是复用,但是复用是在同一客户端和服务器的连接上复用,如果连接过多,服务端的连接会不够用; 短连接:用完就释放。短连接的优点就是不占用连接,可以接受更多的连接请求,确定就是频繁的创建TCP,开销大。 如果请求过多,会有大量的TCP建立释放,如果服务端处理不过来的话,就会常出现很多TIME_WAIT 状态,出现服务不可用的情况。

总结:频繁的请求,还是不要用短连接,不然处理不过来;如果请求不频繁,视情况而定吧。 长短连接遇到的问题: 数据库没有连接池,频繁的做insert,近每分钟10W的insert量,结果一会就出现了连接不够用的情况,系统的load持续彪,出现了大量的TIME_WAIT状态,系统基本死了。 用数据库连接池后,问题就解决了。 https://blog.csdn.net/weixin_41805011/article/details/80452245

https建立连接过程: 客户端请求服务端,服务端使用非对称加密算法生成公钥和私钥,返回证书和公钥,实现秘钥交换。 客户端随机生成对称秘钥,用公钥加密秘钥,用秘钥加密传输信息,传输给服务端 服务端用私钥解密秘钥,用秘钥解密传输信息,获取到信息。

为什么不直接用公钥和私钥加解密信息? 非对称加密比较耗时

三次握手流程? TCP建立连接:三次握手 一般是客户端主动发起请求同服务端建立连接。 客户端发送SYN报文请求建立连接,同时进入SYN_SEND状态。 服务端收到SYN报文后,返回ACK+SYN报文,表示服务端可以支持接收服务端的数据,同时向客户端发送请求,此时服务端进入SYN_RECEIVED状态。 客户端收到ACK+SYN报文后,发送ACK报文,此时客户端进入ESTABLISHED状态;服务端收到ACK后,进入ESTABLISHED状态。

两次握手不行吗? 两次握手是指在服务端收到SYN请求后立即进入ESTABLISHED状态。可能出现的问题是SYN+ACK报文没有到达客户端,造成服务端资源浪费;还有一种情况而客户端重发SYN报文 导致会重新建立连接,资源浪费。

什么是半连接队列和全连接队列? 半连接队列和全连接队列是存放在服务端的。 服务端处于SYN_RECEIVED状态的连接会放在半连接队列里,服务端处于ESTABLISHED状态的连接会放在全连接队列里。

当超过了TCP全连接队列最大长度时,服务端会丢掉后来的TCP连接。 全连接队列满了怎么办? 有策略设置全连接队列满了之后的行为,丢弃是默认行为。 tcp_abort_on_overflow参数控制全连接队列满之后的策略。 =0, 丢弃客户端发过来的ack =1,服务端会发送一个reset包废弃之前和这个客户端建立的连接。此时,客户端调用能看到connection reset by peer 的异常信息。

相比之下,tcp_abort_on_overflow=0能更好地应对突发流量。因为发出的请求因为突发流量导致全连接队列满而丢弃,客户端会执行超时重发的策略,更有利于突发流量峰值之后的恢复。

tcp全连接队列长度最大值取决于somaxconn和backlog的最小值。 somaxconn是linux内核参数,backlog是listen函数的参数,nginx的backlog参数默认是511.

模拟半连接队列溢出,也就是d-dos攻击 半连接队列最大长度不仅参数tcp_max_syn_backlog有关,还与全连接队列是否占满、tcp_syncookies是否打开有关

半连接队列满,只能丢弃吗? 不是 如果开启了syncookies,可以再不使用半连接队列的情况下建立连接,会计算出一个状态值放在ack+syn报文中,客户端返回ack时验证是否合法。

三次握手过程中可以携带数据吗? 前两次不能携带,最后一次可以携带。

dos攻击原理? 其实就是疯狂的发syn报文,但不回复ack报文,导致半连接队列堆满。

四次挥手流程? 客户端发送FIN报文,进入FIN_WAIT1状态,表示想要断开连接;服务器收到FIN报文后,发送ack确认关闭,进入CLOSE_WAIT状态;客户端收到ack后进入FIN_WAIT2状态; 服务器发送完数据后,发送断开连接请求FIN报文,进入LAST_ACK状态;客户端收到FIN报文后,发送ACK报文后,进入TIME_WAIT状态,等待2MSL时间后进入CLOSED状态; 服务端收到ACK报文后,进入CLOSED状态。

挥手流程为什么需要四次,三次不行吗? 交互是双向的,建立连接的时候之所以需要三次的原因是服务端收到请求后,将确认和建立连接的请求同时发送了。

什么是TIME_WAIT状态?TIME_WAIT状态为什么需要等待2MSL? TIME_WAIT是主动发起关闭的一方才有的状态,当客户端收到对方发出的关闭连接的请求时,会进入TIME_WAIT状态。 之所以等待2MSL的原因是,是为了防止发给服务端确认关闭的ack中途丢失,2MSL的时间可以确保服务端在进行超时重传的能收到;另一方面的原因是确保在关闭之前, 所有传输的数据包都已经处理。

TCP CLOSE_WAIT状态明显增多? 正常情况下 CLOSE_WAIT和TIME_WAIT是一个稳定的值,当服务出现故障时,才可能会出现CLOSE_WAIT和TIME_WAIT急剧变化的情况,同时一般会伴随服务器TCP连接数 出现急剧变化的情况。 CLOSE_WAIT状态是服务端收到客户端的关闭请求后,由于自身仍有数据需要发送给客户端,所以会处于CLOSE_WAIT状态,正常情况下负载没有明显变化,CLOSE_WAIT状态 是一个大致稳定的数,突然升高可能是服务某个地方出现了阻塞,导致请求没有处理结束。

TCP TIME_WAIT状态明显减少或增多? 在一次亲身经历的故障中,CLOSE_WAIT状态升高的同时,客户端TIME_WAIT转态明显变少,因为没有收到来自服务端的FIN请求。 大量TIME_WAIT说明是短时间出现了大量的服务端关闭连接的请求。

一个拥塞控制算法一般包括慢启动算法、拥塞避免算法、快速重传算法、快速恢复算法四部分 慢启动是指初始化启动的窗口数量小,随着返回的ack增加,窗口数量成指数级上升; 拥塞避免是窗口数量达到一个阈值后,不再指数级上升,而是+1 快速重传是指在发送端收到连续的(一般是3个)重复ack之后,立即重传报文,不再等待超时时间。 快速恢复是先缩短窗口大小,再根据收到的ack数量调整窗口大小。

对于拥塞控制算法,谷歌提出了tcp拥塞控制算法 传统的基于丢包反馈算法是一种被动式的拥塞控制机制,当出现丢包时,吞吐量会下降 bbr(bottleneck bandwidth and rtt)不以丢包作为判断依据,而是以带宽和RTT这两个指标来进行拥塞控制,优点是尽可能利用带宽,提高吞吐量

quic是quick udp internet connection,也是由谷歌提出,大概是在UDP协议的基础上,实现可靠传输,优点是整合了TCP协议的可靠性和UDP协议的速度

TCP VS UDP协议对比 tcp相比于UDP,传输可靠,双方在通信之前,会通过三次握手建立连接,同时,有流量控制、拥塞控制等机制

应用场景 udp 进行视频聊天或者看直播,因为即使几个画面丢失了,对用户来说影响也不是很大 tcp 发消息的场景以及文件传输,要确保发送的消息不丢失 TCP怎么保证可靠性? (1)序列号、确认应答、超时重传、校验和 tcp报头中有对应的检验和字段,发送的数据包的二进制相加然后取反,目的是检测数据在传输过程中的任何变化。如果收到段的检验和有差错,TCP将丢弃这个报文段和不确认收到此报文段。 数据到达接收方,接收方需要发出一个确认应答,表示已经收到该数据段,并且确认序号会说明了它下一次需要接收的数据序列号。如果发送发迟迟未收到确认应答,那么可能是发送的数据丢失,也可能是确认应答丢失,这时发送方在等待一定时间后会进行重传。这个时间一般是2*RTT(报文段往返时间)+一个偏差值。 (2)窗口控制与高速重发控制/快速重传(重复确认应答) TCP会利用窗口控制来提高传输速度,意思是在一个窗口大小内,不用一定要等到应答才能发送下一段数据,窗口大小就是无需等待确认而可以继续发送数据的最大值。如果不使用窗口控制,每一个没收到确认应答的数据都要重发。 使用窗口控制,如果数据段1001-2000丢失,后面数据每次传输,确认应答都会不停地发送序号为1001的应答,表示我要接收1001开始的数据,发送端如果收到3次相同应答,就会立刻进行重发;但还有种情况有可能是数据都收到了,但是有的应答丢失了,这种情况不会进行重发,因为发送端知道,如果是数据段丢失,接收端不会放过它的,会疯狂向它提醒…… (3)拥塞控制 如果把窗口定的很大,发送端连续发送大量的数据,可能会造成网络的拥堵(大家都在用网,你在这狂发,吞吐量就那么大,当然会堵),甚至造成网络的瘫痪。所以TCP在为了防止这种情况而进行了拥塞控制。

慢启动:定义拥塞窗口,一开始将该窗口大小设为1,之后每次收到确认应答(经过一个rtt),将拥塞窗口大小*2。

拥塞避免:设置慢启动阈值,一般开始都设为65536。拥塞避免是指当拥塞窗口大小达到这个阈值,拥塞窗口的值不再指数上升,而是加法增加(每次确认应答/每个rtt,拥塞窗口大小+1),以此来避免拥塞。

将报文段的超时重传看做拥塞,则一旦发生超时重传,我们需要先将阈值设为当前窗口大小的一半,并且将窗口大小设为初值1,然后重新进入慢启动过程。

快速重传:在遇到3次重复确认应答(高速重发控制)时,代表收到了3个报文段,但是这之前的1个段丢失了,便对它进行立即重传。

然后,先将阈值设为当前窗口大小的一半,然后将拥塞窗口大小设为慢启动阈值+3的大小。

这样可以达到:在TCP通信时,网络吞吐量呈现逐渐的上升,并且随着拥堵来降低吞吐量,再进入慢慢上升的过程,网络不会轻易的发生瘫痪。

面试题: 一台机器最多能支持多少连接? TCP连接的客户端机:每一个ip可建立的TCP连接理论受限于ip_local_port_range参数,也受限于65535。但可以通过配置多ip的方式来加大自己的建立连接的能力。 一条TCP连接是由一个四元组组成的。不考虑地址重用(unix的SO_REUSEADDR选项)的情况下,对于我们这台Nginx Server来说,它的IP和端口是固定的。 tcp连接4元组中只有remote ip(也就是client ip)和remote port(客户端port)是可变的。它可能建立的最大的连接数是2的32次方(ip数)×2的16次方(port数)。 这是2.8*10的14次方的一个大数字,两百万亿!! TCP连接的服务器机:每一个监听的端口虽然理论值很大,但这个数字没有实际意义。最大并发数取决你的内存大小,每一条静止状态的TCP连接大约需要吃3.3K的内存。 https://zhuanlan.zhihu.com/p/290651392

https://www.cnblogs.com/xiaolincoding/p/13067971.html

301 redirect: 301 代表永久性转移(Permanently Moved) 302 redirect: 302 代表暂时性转移(Temporarily Moved )

使用301跳转的场景: 1)域名到期不想续费(或者发现了更适合网站的域名),想换个域名。 2)在搜索引擎的搜索结果中出现了不带www的域名,而带www的域名却没有收录,这个时候可以用301重定向来告诉搜索引擎我们目标的域名是哪一个。 3)空间服务器不稳定,换空间的时候。

使用302跳转的场景: –尽量使用301跳转! https://www.cnblogs.com/biyeymyhjob/archive/2012/07/28/2612910.html

http请求报文有请求行(request line)、请求头(header)、空行和请求数据4个部分组成 请求行 请求行由请求方法字段、URL字段和HTTP协议版本字段3个字段组成,它们用空格分隔。例如,GET /index.html HTTP/1.1。 HTTP协议的请求方法有GET、POST、HEAD、PUT、DELETE、OPTIONS、TRACE、CONNECT GET: POST: POST方式请求行中不包含数据字符串,这些数据保存在”请求内容”部分,各数据之间也是使用”&”符号隔开 HEAD: HEAD就像GET,只不过服务端接受到HEAD请求后只返回响应头,而不会发送响应内容。当我们只需要查看某个页面的状态的时候,使用HEAD是非常高效的,因为在传输的过程中省去了页面内容。

请求头 请求头部由关键字/值对组成,每行一对,关键字和值用英文冒号“:”分隔。请求头部通知服务器有关于客户端请求的信息,典型的请求头有: User-Agent:产生请求的浏览器类型。 Accept:客户端可识别的内容类型列表 。

空行 最后一个请求头之后是一个空行,发送回车符和换行符,通知服务器以下不再有请求头。

请求数据 请求数据不在GET方法中使用,而是在POST方法中使用。与请求数据相关的最常使用的请求头是Content-Type和Content-Length。

http响应报文 http响应报文分为三个部分 状态行、消息报头、响应正文。 http协议默认端口是80 https协议所使用的端口为443 端口作用于传输层上,端口数量65536个 2^16 16位端口号 (1)知名端口号(数值在0~1023) (2)登记端口号(数值在1024~49151) (3)客户端端口号(数值在49152~65535)

UDP是无连接的 UDP是不可靠的 UDP是面向数据报的 UDP没有拥塞控制 https://blog.csdn.net/sandmm112/article/details/80400470 UDP的缓冲区 (1)UDP没有真正意义上的发送缓冲区,当应用层向UDP交付数据时,UDP对数据进行封装之后,直接交给IP层。 (2)UDP具有接受缓冲区。但是接受缓冲区不能保证收到的UDP报文和发送的UDP报文顺序一致。并且一旦接受缓冲区满了,后续到达的UDP报文会被直接丢弃。

ipv6 128位

分布式trace怎么实现? https://siye1982.github.io/2016/04/07/zipkin/ https://segmentfault.com/a/1190000037708223

Updated:

Leave a comment