利用netstat查看http为短连接还是长连接?

最近,公司在做Redis替换memcached的项目,那mc可以设置是长连接,那组件中的Redis到底用的是长连接还是短连接呢?

大牛军哥只给我一个命令:netstat -anp | grep "redis" 查看是否有类似下边的

上图中的代表的就是长连接,很疑惑,我就仔细研究了下,发现很有学问。

一、netstat简介

Netstat 命令用于显示各种网络相关信息,如网络连接,路由表,接口状态 (Interface Statistics),masquerade 连接,多播成员 (Multicast Memberships) 等等。


  
  
  1. Active Internet connections (w/o servers)
  2. Proto Recv-Q Send-Q Local Address Foreign Address State
  3. tcp 0 2 210.34.6.89:telnet 210.34.6.96:2873 ESTABLISHED
  4. tcp 296 0 210.34.6.89:1165 210.34.6.84:netbios-ssn ESTABLISHED
  5. tcp 0 0 localhost.localdom:9001 localhost.localdom:1162 ESTABLISHED
  6. tcp 0 0 localhost.localdom:1162 localhost.localdom:9001 ESTABLISHED
  7. tcp 0 80 210.34.6.89:1161 210.34.6.10:netbios-ssn CLOSE
  8. Active UNIX domain sockets (w/o servers)
  9. Proto RefCnt Flags Type State I-Node Path
  10. unix 1 [ ] STREAM CONNECTED 16178 @000000dd
  11. unix 1 [ ] STREAM CONNECTED 16176 @000000dc
  12. unix 9 [ ] DGRAM 5292 /dev/ log
  13. unix 1 [ ] STREAM CONNECTED 16182 @000000df

从整体上看,netstat的输出结果可以分为两个部分:

一个是Active Internet connections,称为有源TCP连接,其中"Recv-Q"和"Send-Q"指%0A的是接收队列和发送队列。这些数字一般都应该是0。如果不是则表示软件包正在队列中堆积。这种情况只能在非常少的情况见到。

另一个是Active UNIX domain sockets,称为有源Unix域套接口(和网络套接字一样,但是只能用于本机通信,性能可以提高一倍)。
Proto显示连接使用的协议,RefCnt表示连接到本套接口上的进程号,Types显示套接口的类型,State显示套接口当前的状态,Path表示连接到套接口的其它进程使用的路径名。

1.1 常见参数

-a (all)显示所有选项,默认不显示LISTEN相关
-t (tcp)仅显示tcp相关选项
-u (udp)仅显示udp相关选项
-n 拒绝显示别名,能显示数字的全部转化成数字。
-l 仅列出有在 Listen (监听) 的服務状态

-p 显示建立相关链接的程序名
-r 显示路由信息,路由表
-e 显示扩展信息,例如uid等
-s 按各个协议进行统计
-c 每隔一个固定时间,执行该netstat命令。

提示:LISTEN和LISTENING的状态只有用-a或者-l才能看到。

二、netstat中11种网络连接状态

通常情况下,一个正常的TCP连接,都会有三个阶段:

1、TCP三次握手。

2、数据传送。

3、TCP四次挥手。


SYN:(同步序列编号,Synchronize Sequence Numbers)该标志仅在三次握手建立TCP连接时有效。表示一个新的TCP连接请求。 
ACK:(确认编号,Acknowledgement Number)是对TCP请求的确认标志,同时提示对端系统已经成功接收所有数据。 
FIN:(结束标志,FINish)用来结束一个TCP回话.但对应端口仍处于开放状态,准备接收后续数据。 

(1) LISTEN:首先服务端需要打开一个socket进行监听,状态为LISTEN. /* The socket is listening for incoming connections. 侦听来自远方TCP端口的连接请求 */ 

(2) SYN_SENT:客户端通过应用程序调用connect进行active open.于是客户端tcp发送一个SYN以请求建立一个连接.之后状态置为SYN_SENT. /*The socket is actively attempting to establish a connection. 在发送连接请求后等待匹配的连接请求 */ 

(3) SYN_RECV:服务端应发出ACK确认客户端的SYN,同时自己向客户端发送一个SYN. 之后状态置为SYN_RECV /* A connection request has been received from the network. 在收到和发送一个连接请求后等待对连接请求的确认 */ 

(4)ESTABLISHED: 代表一个打开的连接,双方可以进行或已经在数据交互了。/* The socket has an established connection. 代表一个打开的连接,数据可以传送给用户 */ 

(5) FIN_WAIT1:主动关闭(active close)端应用程序调用close,于是其TCP发出FIN请求主动关闭连接,之后进入FIN_WAIT1状态./* The socket is closed, and the connection is shutting down. 等待远程TCP的连接中断请求,或先前的连接中断请求的确认 */ 

(6) CLOSE_WAIT:被动关闭(passive close)端TCP接到FIN后,就发出ACK以回应FIN请求(它的接收也作为文件结束符传递给上层应用程序),并进入CLOSE_WAIT. /* The remote end has shut down, waiting for the socket to close. 等待从本地用户发来的连接中断请求 */ 
  
(7) FIN_WAIT2:主动关闭端接到ACK后,就进入了FIN-WAIT-2 ./* Connection is closed, and the socket is waiting for a shutdown from the remote end. 从远程TCP等待连接中断请求 */ 

(8) LAST_ACK:被动关闭端一段时间后,接收到文件结束符的应用程序将调用CLOSE关闭连接。这导致它的TCP也发送一个 FIN,等待对方的ACK.就进入了LAST-ACK . /* The remote end has shut down, and the socket is closed. Waiting for acknowledgement. 等待原来发向远程TCP的连接中断请求的确认 */ 

(9) TIME_WAIT:在主动关闭端接收到FIN后,TCP就发送ACK包,并进入TIME-WAIT状态。/* The socket is waiting after close to handle packets still in the network.等待足够的时间以确保远程TCP接收到连接中断请求的确认 */

(10) CLOSING: 比较少见./* Both sockets are shut down but we still don't have all our data sent. 等待远程TCP对连接中断的确认 */ 

(11) CLOSED: 被动关闭端在接受到ACK包后,就进入了closed的状态。连接结束./* The socket is not being used. 没有任何连接状态 */ 

TIME_WAIT状态的形成只发生在主动关闭连接的一方。 

    主动关闭方在接收到被动关闭方的FIN请求后,发送成功给对方一个ACK后,将自己的状态由FIN_WAIT2修改为TIME_WAIT,而必须再等2倍 的MSL(Maximum Segment Lifetime,MSL是一个数据报在internetwork中能存在的时间)时间之后双方才能把状态 都改为CLOSED以关闭连接。目前RHEL里保持TIME_WAIT状态的时间为60秒。 
  

当然上述很多TCP状态在系统里都有对应的解释或设置,可见man tcp 

三、netstat使用

3.1 找出程序运行的端口

# netstat -ap | grep ssh

3.2 IP和TCP分析

 1、查看连接某服务端口最多的的IP地址

# netstat -nat | grep "192.168.1.15:22" |awk '{print $5}'|awk -F: '{print $1}'|sort|uniq -c|sort -nr|head -20

  2、TCP各种状态列表并统计排序

 # netstat -nat |awk '{print $6}'|sort|uniq -c|sort -rn

  3、分析access.log获得访问前10位的ip地址

  #  awk '{print $1}' access.log | sort | uniq -c | sort -nr | head -10

  4、显示所有80端口的网络连接并排序。这里的80端口是http端口,所以可以用来监控web服务。如果看到同一个IP有大量连接的话就可以判定单点流量攻击了。

   # netstat -an | grep :80 | sort

 5、这个命令可以查找出当前服务器有多少个活动的 SYNC_REC 连接。正常来说这个值很小,最好小于5。 当有Dos攻击或者邮件炸弹的时候,这个值相当的高。尽管如此,这个值和系统有很大关系,有的服务器值就很高,也是正常现象。

netstat -np | grep SYN_REC | wc -l

6、列出所有连接过的IP地址。

netstat -n -p | grep SYN_REC | sort -u

7、列出所有发送SYN_REC连接节点的IP地址。

netstat -n -p | grep SYN_REC | awk '{print $5}' | awk -F: '{print $1}'

8、使用netstat命令计算每个主机连接到本机的连接数。

netstat -ntu | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -n

9、列出所有连接到本机的UDP或者TCP连接的IP数量。

netstat -anp |grep 'tcp|udp' | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -n

10、检查 ESTABLISHED 连接并且列出每个IP地址的连接数量。

netstat -ntu | grep ESTAB | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -nr

netstat -plan|grep :80|awk {'print $5'}|cut -d: -f 1|sort|uniq -c|sort -nk 1
 

四、关于长连接和短连接

先带你来认识一下它俩的区别。

长连接意味着进行一次数据传输后,不关闭连接,长期保持连通状态。如果两个应用程序之间有新的数据需要传输,则直接复用这个连接,无需再建立一个新的连接。就像下图这样。

它的优势是在多次通信中可以省去连接建立和关闭连接的开销,并且从总体上来看,进行多次数据传输的总耗时更少。缺点是需要花费额外的精力来保持这个连接一直是可用的,因为网络抖动、服务器故障等都会导致这个连接不可用,甚至是由于防火墙的原因。所以,一般我们会通过下面这几种方式来做“保活”工作,确保连接在被使用的时候是可用状态:

  1. 利用 TCP 自身的保活(Keepalive)机制来实现,保活机制会定时发送探测报文来识别对方是否可达。一般的默认定时间隔是 2 小时,你可以根据自己的需要在操作系统层面去调整这个间隔,不管是 Linux 还是 Windows 系统。
  2. 上层应用主动的定时发送一个小数据包作为“心跳”,探测是否能成功送达到另外一端。 保活功能大多数情况下用于服务端探测客户端的场景,一旦识别客户端不可达,则断开连接,缓解服务端压力。

提前多说一句,如果在做了高可用的分布式系统场景中运用长连接会更麻烦一些。因为高可用必然包含自动故障转移、故障隔离等机制。这恰恰导致了一旦发生故障,客户端需要及时发现哪些连接已处于不可用状态,并进行相应的重连,包括重新做负载均衡等工作。

了解完了长连接,那么短连接就很容易理解了。短连接意味着每一次的数据传输都需要建立一个新的连接,用完再马上关闭它。下次再用的时候重新建立一个新的连接,如此反复。

它的优势是由于每次使用的连接都是新建的,所以基本上只要能够建立连接,数据就大概率能送达到对方。并且哪怕这次传输出现异常也不用担心影响后续新的数据传输,因为届时又是一个新的连接。缺点是每个连接都需要经过三次握手和四次握手的过程,耗时大大增加。

另外,短连接还有一个致命的缺点。我们回到前面提到的维基百科对 socket 的定义,其中说到socket 包含通信协议、目标地址、状态等。实际当你在基于 socket 进行开发的时候,这些包含的具体资源主要就是这 5 个:源 IP、源端口、目的 IP、目的端口、协议,有个专业的叫法称之为“五元组”。在一台计算机上只要这五元组的值不重复,那么连接就可以被建立。然而一台计算机最多只能开启 65535 个端口,如果现在两个进程之间需要通信,作为服务端的 IP 和端口必然是固定的,因此单个客户端理论上最多只能与服务端同时建立 65535 个 socket 连接。如果除去操作系统和其它进程所占用的端口,实际还会更少。所以,一旦使用不当,在很短的时间内建立了大量连接,端口很容易被占用完。这不但会导致自身无法正常工作,还会影响到同一台计算机上的其它进程。

我猜你在项目中大多数情况使用的是短连接的方式,因为这对我们编程来说可以少考虑很多问题,潜在的这些缺点可能是你没有遇到或者意识到而已。存在必有其价值,接下去我们根据实际的案例让你清楚知道如何来选择它们。

五、长连接和短连接的选择

我想你肯定见过一些监控或者实时报价类系统,比如股票软件,它需要在几秒之内刷新最新的价格。像这种场景中同时包含了需要运用长连接的三个主要因素:高频、服务端主动推送和有状态。

  • 高频的原因我想你根据前面的内容也明白了,因为频次越高的话,使用短连接带来的建立连接和关闭连接的总开销越大。
  • 而服务端主动推送也需要长连接的原因是,由于服务端往往是“中心化”的,一般都是 1 个服务端为多个客户端提供服务。所以,如果使用短连接的方式,那么在客户端未主动连接到服务端的情况下,服务端并不知道需要往哪些客户端去推送数据,这是原因之一。所以此时,长连接成为了一个很好的选择。另外一个原因是,哪怕客户端通过定时的短连接轮询方式进行主动连接,除了增加了额外的建立连接和关闭连接的开销外,还可能遇到通信完成后结果数据并未发生变化,做了无用功。
  • 成熟股票软件的服务端,为了支撑更多的用户以及做高可用,必然部署了多台。但是这个业务场景,用户无法容忍由于多个服务端之间数据同步的误差导致他在客户端看到的价格刷新产生“回退”现象。所以,只能尽量保持一直连接在同一台服务器上,才能避免这个情况。这种场景被称之为“有状态”,也可以理解为是“串行”的,因为多次请求的前后需要保持“连续性”。

短连接则更适用于诸如阅读类软件的场景中,例如,很多时候用户点开一篇文章后需要花一些时间进行阅读,这个时间有长有短,并且直到用户下一次操作之前都没有数据传输发生。这个场景中包含了运用短连接的两个主要因素:低频、无状态。

  • 因为低频,所以更能容忍建立连接和关闭连接的开销。
  • 用户的下一次点击往往跳转到了其它文章,并且新打开的与当前文章并不需要具有“连续性”,所以这种场景我们称之为“无状态”的。另外,理论上同一时刻打开几篇文章也不会存在什么不妥。

通过这两个案例我们可以总结出一个决定何时运用长连接和短连接的最佳实践。

长连接适用于:两个进程之间需要高频通信并且具备服务端主动推送或者有状态(需串行)两者之一的场景,否则并不是必选项。

短连接适用于:两个进程之间通信频率较低,或者属于无状态(可并行)的场景,否则并不是必选项。

其它情况就根据所需的侧重点来,比如侧重性能就长连接,侧重编码的便捷性就选择短连接。

———————————————

参考文档:

1、https://blog.csdn.net/alibo2008/article/details/21523809

2、如何使用netstat命令验证DDOS入侵

3、https://www.cnblogs.com/ggjucheng/archive/2012/01/08/2316661.html

4、https://blog.csdn.net/Listen2You/article/details/82950763

5、https://cloud.tencent.com/developer/article/1470024

发布了8 篇原创文章 · 获赞 18 · 访问量 8862

猜你喜欢

转载自blog.csdn.net/weixin_38054045/article/details/104155681