Chinaunix首页 | 论坛 | 博客
  • 博客访问: 505987
  • 博文数量: 176
  • 博客积分: 4045
  • 博客等级: 上校
  • 技术积分: 2491
  • 用 户 组: 普通用户
  • 注册时间: 2008-03-19 11:23
文章分类

全部博文(176)

文章存档

2011年(7)

2009年(12)

2008年(157)

我的朋友

分类:

2008-06-22 10:22:25

以前写过一篇文章,用来统计tcp连接总数,这周发现有时候也需要统计详细的tcp套接字信息,以便分析具体问题。
    今天用awk写了个小脚本,用来统计各种tcp状态的详细信息,之所以不用netstat工具,是因为此君实在是慢,在笔者一台总连接数只有5147的机 器上,netstat统计出来用了11秒,我写的脚本用了2.7秒,特别是在大负载的服务器环境,随着连接数的提高,这种效率的提高是必须考虑的,就是一 种工作态度吧,不能只把事情做出来,要考虑怎么样做才是最好的方式,节省服务器的资源,可以让我们sa的工作更加轻松,ok,先看看时间比对:
 
纯粹的netstat:
[root@a work]# time netstat -an 2>/dev/null > c
real    0m11.130s
user    0m0.156s
sys     0m10.929s
 
偶写的awk脚本:
[root@a work]# time sh netstat-detail.sh > b
real    0m2.725s
user    0m0.288s
sys     0m2.416s
 
这个脚本中最费时的是这一步:
[root@a work]# time cat /proc/net/tcp /proc/net/tcp6 2>/dev/null > a
real    0m2.619s
user    0m0.004s
sys     0m2.592s
 
也就是说,如果能突破从proc下快速取文件的瓶颈,这个速度肯定能飞升,可是偶还深入不了这么深的深度,暂时只能做到这样啦。
下面是详细的脚本代码,希望能给各位从事sa的同仁们所用
 
#! /bin/sh
cat /proc/net/tcp /proc/net/tcp6 2>/dev/null > a
awk '{print $2,$3,$4}' /tmp/a | awk '
BEGIN { # set fs
        FS = "[ ]*|:" ;
  # print header
        printf("Local-Address Foreign-Address State\n");   }
# drop trash message from file tcp && tcp6
( $0 !~ /local_address/ ){
# get ipv4addr from file /proc/net/tcp
if (length($1) == 8)
{
 local_addr_ip4 = strtonum("0x"substr($1,1,2)) ;
 local_addr_ip3 = strtonum("0x"substr($1,3,2)) ;
 local_addr_ip2 = strtonum("0x"substr($1,5,2)) ;
 local_addr_ip1 = strtonum("0x"substr($1,7,2)) ;
 rem_addr_ip4 =  strtonum("0x"substr($3,1,2)) ;
 rem_addr_ip3 =  strtonum("0x"substr($3,3,2)) ;
 rem_addr_ip2 =  strtonum("0x"substr($3,5,2)) ;
 rem_addr_ip1 =  strtonum("0x"substr($3,7,2)) ;
}
else
# get ipv6addr from file /proc/net/tcp6
{
 local_addr_ip4 = strtonum("0x"substr($1,25,2)) ;
 local_addr_ip3 = strtonum("0x"substr($1,27,2)) ;
 local_addr_ip2 = strtonum("0x"substr($1,29,2)) ;
 local_addr_ip1 = strtonum("0x"substr($1,31,2)) ;
 rem_addr_ip4 =  strtonum("0x"substr($3,25,2)) ;
 rem_addr_ip3 =  strtonum("0x"substr($3,27,2)) ;
 rem_addr_ip2 =  strtonum("0x"substr($3,29,2)) ;
 rem_addr_ip1 =  strtonum("0x"substr($3,31,2)) ;
}
local_port = strtonum("0x"$2) ;
rem_port = strtonum("0x"$4) ;
# analyze $5 tcp stat
if ( $5 ~ /06/ ) tcp_stat = "TIME_WAIT"
else if ( $5 ~ /02/ ) tcp_stat = "SYN_SENT"
else if ( $5 ~ /03/ ) tcp_stat = "SYN_RECV"
else if ( $5 ~ /04/ ) tcp_stat = "FIN_WAIT1"
else if ( $5 ~ /05/ ) tcp_stat = "FIN_WAIT2"
else if ( $5 ~ /01/ ) tcp_stat = "ESTABLISHED" ;
else if ( $5 ~ /07/ ) tcp_stat = "CLOSE"
else if ( $5 ~ /08/ ) tcp_stat = "CLOSE_WAIT"
else if ( $5 ~ /09/ ) tcp_stat = "LAST_ACK"
else if ( $5 ~ /0A/ ) tcp_stat = "LISTEN"
else if ( $5 ~ /0B/ ) tcp_stat = "CLOSING"
else if ( $5 ~ /0C/ ) tcp_stat = "MAX_STATES"

printf("%d.%d.%d.%d:%d %d.%d.%d.%d:%d %s\n",local_addr_ip1,local_addr_ip2,local_addr_ip3,local_addr_ip4,local_port,rem_addr_ip1,rem_addr_ip2,rem_addr_ip3,rem_addr_ip4,rem_port,tcp_stat);
 
}' | column -t

# experience : first column of tcp && tcp6 is not settled ! may "  1" may "134562" so it is difficult to set the very fs !!
之所以加上最后的经验说明,是因为刚开始的时候只想着一次取a的内容,分析完毕,可是后面发现tcp中第一列的内容不怎么规则,有的位数多了,超过1000,就没有空格了,这个给设置fs造成了非常大的麻烦,最后我才不得以直接用管道取出a的2345列。
   附上此脚本的输出示例吧(服务和端口信息都是修改过的,以免泄露机密^_^):
[root@localhost tmp]# sh netstat-detail.sh
Local-Address         Foreign-Address      State
0.0.0.0:44          0.0.0.0:0            LISTEN
0.0.0.0:23          0.0.0.0:0            LISTEN
0.0.0.0:80            0.0.0.0:0            LISTEN
127.0.0.1:26          0.0.0.0:0            LISTEN
0.0.0.0:6           0.0.0.0:0            LISTEN
127.0.0.1:6       127.0.0.1:6      ESTABLISHED
233.178.12.266:72     222.35.231.188:1257  ESTABLISHED
0.0.0.0:6         0.0.0.0:0            LISTEN
127.0.0.1:6        0.0.0.0:0            LISTEN
0.0.0.0:6          0.0.0.0:0            LISTEN
233.178.12.266:6  0.0.0.0:0            LISTEN
127.0.0.1:6       127.0.0.1:56     ESTABLISHED
[root@localhost tmp]#
[root@localhost tmp]# netstat -an
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address               Foreign Address             State     
tcp        0      0 0.0.0.0:76                0.0.0.0:*                   LISTEN     
tcp        0      0 0.0.0.0:6                0.0.0.0:*                   LISTEN     
tcp        0      0 0.0.0.0:6                 0.0.0.0:*                   LISTEN     
tcp        0      0 127.0.0.1:26                0.0.0.0:*                   LISTEN     
tcp        0      0 0.0.0.0:6                0.0.0.0:*                   LISTEN     
tcp        0      0 127.0.0.1:6            127.0.0.1:56827             ESTABLISHED
tcp        0    908 233.178.12.266:6         222.35.231.128:1257         ESTABLISHED
tcp        0      0 :::6                     :::*                        LISTEN     
tcp        0      0 ::ffff:127.0.0.1:6       :::*                        LISTEN     
tcp        0      0 :::86                    :::*                        LISTEN     
tcp        0      0 ::ffff:233.178.12.266:26 :::*                        LISTEN     
tcp        0      0 ::ffff:127.0.0.1:566    ::ffff:127.0.0.1:56822      ESTABLISHED
Active UNIX domain sockets (servers and established)
Proto RefCnt Flags       Type       State         I-Node Path
unix  2      [ ACC ]     STREAM     LISTENING     16986424
unix  2      [ ]         DGRAM                    16986405
unix  2      [ ]         DGRAM                    4505  
unix  2      [ ]         DGRAM                    4427  
 
 
    还有一个小的细节就是在做if判断是,偶把最频繁出现的放在了第一个比较上,比如tcp的状态比tcp6的多,tcp状态中TIME_WAIT肯定最多 (不开启复用的话)所以,都在各自的if中放在了第一个比对条件,据说这样也可以提高效率,没有时间了,要陪老婆去民族园玩啦,呵呵。
阅读(2137) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~