tcp-http

58 阅读7分钟

TCP_UDP_HTTP

TCP_state

tcp.png

主动/被动是从client角度进行解释的.

TCP_connection

3次握手

  1. C -> S : 发送SYN标记的报文(中间状态:c-syn_send,s:syn_rcvd)
  2. S -> C : 发送ACK, SYN 2个标记的报文
  3. C -> S : 发送ACK, 报文(带数据)

建立链接时状态的变化

  • 服务端: CLOSED -> LISTEN -> SYN_RCVD -> ESTABLISHED
  • 客户端: CLOSED -> SYN_SEND -> ESTABLISHED

SYN_SEND: SYN has been send SYN_RCVD: SYN has been rcvd

TCP_connection_close

  • 全双工(断开的是数据传输方向),需要断开2次
  1. C->S: 发送FIN

  2. S->C: 发送ACK(关闭client -> Server的数据传输, 但是客户端还可以发送ack)

  3. S->C : FIN

  4. C->S : ACk (关闭server -> Client的数据传输,谁发送就断开谁)

主动关闭/被动关闭

如上图,·主动/被动是站在app(client)的角度

  • 主动关闭:客户端先发起的FIN:EXTABLISH->TIME_WAIT->CLOSED

    • Server端的TIME_WAIT时间一直使用端口
    • TIME_WAIT阶段可能发生SOCKET IN USE ERROR;server端在等待2MSL时一直占用端口;所以需要优雅关机
    • TIME_WAIT:主动关闭时,server和client之间的4次握手全部完成时,server需要继续等待关闭的时间,默认2MSL
  • 被动关闭:客户端后发起FIN:ESTABLISHED->CLOSE_WAIT->LAST_ACK->CLOSED

    • 简单点: ESTABLISHED -> CLOSE_WAIT -> CLOSED
    • CLOSE_WAIT: 等待客户端发起FIN,并发送LAST_ACK(server不会再发送数据了)

keeplive_connection

长链接不像短链接一样每个请求建立一次TCP链接,而是多个请求共用一个TCP链接; 所以在配置长链接是一般需要从2个角度的配置 长链接的超时时间长链接允许的最大请求数; 长链接省去了tcp三次握手的时间。

ping一下大约0.93ms(一次往返)相当于三次握手也是一次往返(TCP第三次握手不用返回);即tcp链接省去了ping一次的耗时;假如你的服务每天的pv是1亿,那么使用长连接节约的总时间为:1亿1ms=10^81ms=10^51s=10^51h/3600≈27.78h。神奇的是,亿万级pv的服务使用长连接一天内节约的总时间为27.78小时(竟然大于一天)

keepalive_config

优化web服务设置长链接2个方面: client - nginx, nginx - tomcat;

client_nginx

  1. 客户端设置请求头Keep-Alive
  2. nginx 设置 keepalive
# conf/nginx.conf
http{
    keepalive_timeout 300s 120s;
    keepalive_requests 300;
}

keepalive_timeout timeout [header_timeout]

  1. timeout: 设置keep-alive的客户端连接在服务器端保持开启的超时值,单位S,表示一个长链接在nginx端的超时时间timout秒后nginx会主动断开,timout默认75s,值为0会禁用keep-alive客户端连接;
  2. header_timeout 可选,在响应请求的的header域中设置Keep-Alive: timeout=time

keepalive_requests 100 默认100, 客户端长链接在nginx端能处理请求的最大数量,nginx对每个TCP链接设置计数器,当处理的http请求数达到上限,则断开链接.

keepalive_requests设置较小且QPS(PV)访问过大时, nginx主动断开链接, netstat客户端服务器,会出现大量的TIME_WAIT

nginx_tomcat

    1. 在nginx端设置upstream
upstream{
   keepalive 1000;
}
location{
    proxy_http_version 1.1;
    proxy_set_header Connection "";
}

keepalive 1000: 每个worker进程保持的到upstream服务器的最大的空闲长连接数; 不是woker进程到upstream的最大长连接数; proxy_http_version 1.1; http 1.1 版本支持长链接 proxy_set_header Connection "";清空client端请求的header,即使在client-nginx是短链接的情况下,不影响nginx-tomcat之间建立长链接

    1. tomcat配置conf/server.xml
<Connector port="8080"
protocol="org.apache.coyote.http11.Http11NioProtocol"# 支持非阻塞IO
maxThreads="768" # 连接器创建的处理请求的最大线程数
minSpareThreads="512" # 最小空闲县城
acceptCount="128"  # accept请求链接的队列长度
connectionTimeout="1000"  #等待时间
maxConnections="1024" # 服务器最大的链接
keepAliveTimeout="300000" # 长链接超时
maxKeepAliveRequests="768" # 长链接请求数
enableLookups="false" # 禁用DNS查询
URIEncoding="UTF-8" #默认是ISO,有可能导致get参数中文乱码,设置为UTF-8
redirectPort="8443"
compression="on" # 连接器是否启用HTTP/1.1GZIP压缩为了节省服务器带宽
compressionMinSize="1024" # 相应数据的最小大小
compressableMimeType="text/html,text/xml,text/javascript,text/css,text/plain,application/json,application/xml" # http压缩的文件类型
server="webserver" /> # http 相应头的Server信息

key

Q

为什么建立连接协议是三次握手,而关闭连接却是四次握手呢

三次握手建立链接时,ACK+SYN一起发送 或者 ACK+数据 一起发送时能够节省是为了提高发送的效率;节省传输的时间;

四次握手断开链接时; FIN和ACK没有一起发送是 因为 TCP是全双工的链接,数据双向传输; FIN表示发送方不再发送数据;当一方发送FIN时,需要立刻收到ACK回复;但另一方仍然可能需要继续发送数据,所以不能立即发送FIN, 所以FIN 和 ACK 不能在一起发送, 从而需要4次握手

为什么TIME_WAIT状态还需要等2MSL后才能返回到CLOSED状态

TIME_WAIT 出现在主动关闭链接时,服务端4次握手全部完成时等待的状态,为了防止因为网络问题服务端最后发送的ACK客户端没有收到,客户端此时会重新发送FIN, 此时服务端可以用来重新发送ACK

什么情况下出现TIME_WAIT,有什么用?系统配置解决大量的TIME_WAIT

一般出现的在主动关闭链接时,客户端和服务端使用短链接,而且频繁的出现 建立链接 + 断开链接 操作

netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
# TIME_WAIT 48    #主动关闭的链接,  
# CLOSE_WAIT 2228 #被动关闭的链接,半关闭, client不再发送数据
# ESTABLISHED 86  #建立的链接

解决方案1: 配置长链接,处理好http链接的关闭问题

## tcp相关的系统配置: vim /etc/sysctl.conf
## 编辑完 /etc/sysctl.conf,要重启network 才会生效 /etc/rc.d/init.d/network restart 
## 然后,执行sysctl命令使修改生效,基本上就算完成了。
#表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭;
net.ipv4.tcp_syncookies=1
#表示开启重用。允许将TIME_WAIT sockets重新用于新的TCP连接,默认为0,表示关闭; 
net.ipv4.tcp_tw_reuse = 1
#表示开启TCP连接中TIME_WAIT sockets的快速回收,默认为0,表示关闭;
net.ipv4.tcp_tw_recycle = 1   
# 修改系統默认的 TIMEOUT 时间
net.ipv4.tcp_fin_timeout=30
#表示当keepalive起用的时候,TCP发送keepalive消息的频度。缺省是2小时,改为20分钟。
net.ipv4.tcp_keepalive_time = 1200
#表示用于向外连接的端口范围。缺省情况下很小:32768到61000,改为1024到65000。
net.ipv4.ip_local_port_range = 1024 65000
#表示SYN队列的长度,默认为1024,加大队列长度为8192,可以容纳更多等待连接的网络连接数。    
net.ipv4.tcp_max_syn_backlog = 8192
#表示系统同时保持TIME_WAIT套接字的最大数量,如果超过这个数字,TIME_WAIT套接字将立刻被清除并打印警告信息。  默认为180000,改为5000。对于Apache、Nginx等服务器,上几行的参数可以很好地减少TIME_WAIT套接字数量,但是对于 Squid,效果却不大。此项参数可以控制TIME_WAIT套接字的最大数量,避免Squid服务器被大量的TIME_WAIT套接字拖死。
net.ipv4.tcp_max_tw_buckets = 5000

TCP/UDP的定义的不同,TCP如何实现有序传输.解释TCP快速重传,拥塞机制,怎么解决粘包问题

tcp的转包工具:tcpdump

Https与Http的区别,解决的什么问题?如何实现的

  • 网络传输的协议层:(http请求涉及的协议)
    • 应用层:HTTP/DNS(域名解析协议:domain-ip)/FTP
    • 传输层:TCP/UDP
    • 网络层:IP/ARP(address resolution protocol地址解析协议:根据IP获取mac)
    • 数据链路层
  • HTTP + SSL = HTTPS(TSL是SSL的升级版本,主要为了解决数据传输的安全问题)
    • 对称加密: 可能存在密钥泄漏的问题
    • 非对称加密: 可能出现虚假中介问题
    • 非对称加密 + CA充当权威第三方 => openssl 完成

java.net.SocketException

导致“Connection reset”的原因是服务器端因为某种原因关闭了Connection,而客户端依然在读写数据,此时服务器会返回复位标志RST,然后此时客户端就会提示java.net.SocketException: Connection reset

  • Connection reset: 服务器返回了“RST”时,如果此时客户端正在从Socket套接字的输出流中读数据则会抛
  • Connection reset by peer:服务器返回了“RST”时,如果此时客户端正在往Socket套接字的输入流中写数据则会抛

cdn的配置与使用