comet模型的主机维持长连接,单台连接接数可以达到百万(现网目前用的最高单台可达到60万左右),在统计网络连接状态时会netstat会长期不响应,而SS命令统计相对较快,不过输出不够美观 。本篇主要总结下comet模型下的连接数常见统计方法。tcp连接主机是通过读取/proc/net/tcp文件进行的统计。具体每项值的意思见下图(点击可查看大图)

一、C++ 代码实现连接数统计

  1[root@361way netstat]# cat ss++.cc
  2// code from www.361way.com
  3#include<iostream>
  4#include<fstream>
  5#include<cstdlib>
  6#include<sstream>
  7using namespace std;
  8//struct: Property of a tcp connection
  9struct ConnectionProperty
 10{
 11    string local_addr;
 12    string remote_addr;
 13    string state;
 14};
 15//Change hexadecimal number to decimal number
 16int HexToInt(char h)
 17{
 18    if(h >= '0' && h <= '9')
 19    {
 20        return h - '0';
 21    }
 22    else if(h >= 'A' && h <= 'F')
 23    {
 24        return h - 'A' + 10;
 25    }
 26    else
 27    {
 28        cerr << "Error: Illegal Hex Number!" << endl;
 29        return -1;
 30    }
 31}
 32//Get Ip address and port number from string XXXXXXXX:XXXX
 33string GetIpAddress(char* str)
 34{
 35    int a, b, c, d, e;
 36    a = HexToInt(str[0]) * 16 + HexToInt(str[1]);
 37    b = HexToInt(str[2]) * 16 + HexToInt(str[3]);
 38    c = HexToInt(str[4]) * 16 + HexToInt(str[5]);
 39    d = HexToInt(str[6]) * 16 + HexToInt(str[7]);
 40    e = HexToInt(str[9]) * 16 * 16 * 16 +
 41        HexToInt(str[10]) * 16 * 16 +
 42        HexToInt(str[11]) * 16 +
 43        HexToInt(str[12]);
 44    //change int to string
 45    string sa, sb, sc, sd, se;
 46    ostringstream oss;
 47    oss << a;
 48    sa = oss.str();
 49    oss.str(""); //clear the content in oss
 50    oss << b;
 51    sb = oss.str();
 52    oss.str("");
 53    oss << c;
 54    sc = oss.str();
 55    oss.str("");
 56    oss << d;
 57    sd = oss.str();
 58    oss.str("");
 59    oss << e;
 60    se = oss.str();
 61    oss.str("");
 62    //return by order: d.c.b.a:e
 63    return sd + '.' + sc + '.' + sb + '.' + sa + ':' + se;
 64}
 65//Get tcp connection state
 66string GetConnectionState(char* str)
 67{
 68    if(str[0] == '0' && str[1] == '0') return "ERROR_STATUS";
 69    if(str[0] == '0' && str[1] == '1') return "TCP_ESTABLISHED";
 70    if(str[0] == '0' && str[1] == '2') return "TCP_SYN_SENT";
 71    if(str[0] == '0' && str[1] == '3') return "TCP_SYN_RECV";
 72    if(str[0] == '0' && str[1] == '4') return "TCP_FIN_WAIT1";
 73    if(str[0] == '0' && str[1] == '5') return "TCP_FIN_WAIT2";
 74    if(str[0] == '0' && str[1] == '6') return "TCP_TIME_WAIT";
 75    if(str[0] == '0' && str[1] == '7') return "TCP_CLOSE";
 76    if(str[0] == '0' && str[1] == '8') return "TCP_CLOSE_WAIT";
 77    if(str[0] == '0' && str[1] == '9') return "TCP_LAST_ACK";
 78    if(str[0] == '0' && str[1] == 'A') return "TCP_LISTEN";
 79    if(str[0] == '0' && str[1] == 'B') return "TCP_CLOSING";
 80    return "UNKNOWN_STATE";
 81}
 82int main()
 83{
 84    //read from file /proc/net/tcp
 85    ifstream infile("/proc/net/tcp", ios :: in);
 86    if(!infile)
 87    {
 88        cerr << "open error!" << endl;
 89        exit(1);
 90    }
 91    string s;
 92    char s_local_addr[20], s_remote_addr[20], s_state[20];
 93    getline(infile, s); //title: every column's name
 94    while(getline(infile, s))
 95    {
 96        sscanf(s.c_str(), "%*s%s%s%s", s_local_addr, s_remote_addr, s_state);
 97        //printf("%s\t%s\t%s\n", s_local_addr, s_remote_addr, s_state);
 98        string ip_local = GetIpAddress(s_local_addr);
 99        string ip_remote = GetIpAddress(s_remote_addr);
100        string conn_state = GetConnectionState(s_state);
101        cout << ip_local << "\t" << ip_remote << "\t" << conn_state << endl;
102    }
103    return 0;
104}

通过如下代码编译生成可执行文件: g++ -o netinfo ss++.cc,执行输出如下:

1[root@comethost ~]# ./netinfo
2115.28.174.118:5224       121.31.251.8:13351      TCP_ESTABLISHED
3115.28.174.118:5229       223.104.23.84:62815     TCP_ESTABLISHED
4115.28.174.118:5225       117.136.79.70:45116     TCP_ESTABLISHED
5115.28.174.118:5224       112.17.243.208:33236    TCP_ESTABLISHED
6115.28.174.118:5224       27.204.14.135:44976     TCP_ESTABLISHED
7115.28.174.118:5228       58.18.233.29:60135      TCP_ESTABLISHED
8115.28.174.118:5226       112.17.246.84:26055     TCP_ESTABLISHED

二、python实现tcp连接统计

 1#!/usr/bin/env python
 2# code from www.361way.com
 3# coding=utf-8
 4import pwd
 5import os
 6import re
 7import glob
 8PROC_TCP = "/proc/net/tcp"
 9STATE = {
10        '01':'ESTABLISHED',
11        '02':'SYN_SENT',
12        '03':'SYN_RECV',
13        '04':'FIN_WAIT1',
14        '05':'FIN_WAIT2',
15        '06':'TIME_WAIT',
16        '07':'CLOSE',
17        '08':'CLOSE_WAIT',
18        '09':'LAST_ACK',
19        '0A':'LISTEN',
20        '0B':'CLOSING'
21        }
22def _load():
23    ''' Read the table of tcp connections & remove header  '''
24    with open(PROC_TCP,'r') as f:
25        content = f.readlines()
26        content.pop(0)
27    return content
28def _hex2dec(s):
29    return str(int(s,16))
30def _ip(s):
31    ip = [(_hex2dec(s[6:8])),(_hex2dec(s[4:6])),(_hex2dec(s[2:4])),(_hex2dec(s[0:2]))]
32    return '.'.join(ip)
33def _remove_empty(array):
34    return [x for x in array if x !='']
35def _convert_ip_port(array):
36    host,port = array.split(':')
37    return _ip(host),_hex2dec(port)
38def netstat():
39    '''
40    Function to return a list with status of tcp connections at linux systems
41    To get pid of all network process running on system, you must run this script
42    as superuser
43    '''
44    content=_load()
45    result = []
46    for line in content:
47        line_array = _remove_empty(line.split(' '))     # Split lines and remove empty spaces.
48        l_host,l_port = _convert_ip_port(line_array[1]) # Convert ipaddress and port from hex to decimal.
49        r_host,r_port = _convert_ip_port(line_array[2])
50        state = STATE[line_array[3]]
51        nline = [ l_host+':'+l_port, r_host+':'+r_port, state ]
52        result.append(nline)
53    return result
54if __name__ == '__main__':
55    for conn in netstat():
56        print conn

三、ss统计

默认安装完iproute2包后,里面包含有ss工具,不过想要查看ss的源码可以到https://github.com/shemminger/iproute2/blob/master/misc/ss.c 查看 。

四、统计速率统计

这里只找了一台连接数在20多万的comet服务器进行的测试,从执行效果来看:

  1. ss -nt执行速度最快
  2. c++版的netinfo与ss接近(稍慢于c语言版的ss)
  3. python版的比ss与netinfo慢五到六倍
  4. netstat没做测试,根据之前的了解,估计与python版的接近或者差于python版的

所以后续现网有简单的连接数统计需求,会优先选择c++版的ss(输出美观),而且可以在此基础上简单定制 。

参考页面:

c++版的ss参考oschina

python版的ss参考 voorloopnul

相关代码已上传至我的github :https://github.com/361way/python/tree/master/netstat