成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Go 語言實現簡易版 netstat 命令

開發 后端
netstat 使用 go 語言實現是什么操作?本文從 netstat 原理出發詳細解讀了這一實踐。

  netstat 使用 go 語言實現是什么操作?本文從 netstat 原理出發詳細解讀了這一實踐。

netstat 工作原理

netstat 命令是 linux 系統中查看網絡情況的一個命令。比如我們可以通過netstat \-ntlp | grep 8080查看監聽 8080 端口的進程。

netstat 工作原理如下:

  1.  通過讀取/proc/net/tcp 、/proc/net/tcp6 文件,獲取 socket 本地地址,本地端口,遠程地址,遠程端口,狀態,inode 等信息
  2.  接著掃描所有/proc/[pid]/fd 目錄下的的 socket 文件描述符,建立 inode 到進程 pid 映射
  3.  根據 pid 讀取/proc/[pid]/cmdline 文件,獲取進程命令和啟動參數
  4.  根據 2,3 步驟,即可以獲得 1 中對應 socket 的相關進程信息

我們可以做個測試驗證整個流程。先使用 nc 命令監聽 8090 端口: 

  1. nc -l 8090 

找到上面 nc 進程的 pid,查看該進程所有打開的文件描述符: 

  1. vagrant@vagrant:/proc/25556/fd$ ls -alh  
  2. total 0  
  3. dr-x------ 2 vagrant vagrant  0 Nov 18 12:21 .  
  4. dr-xr-xr-x 9 vagrant vagrant  0 Nov 18 12:20 ..  
  5. lrwx------ 1 vagrant vagrant 64 Nov 18 12:21 0 -> /dev/pts/1  
  6. lrwx------ 1 vagrant vagrant 64 Nov 18 12:21 1 -> /dev/pts/1  
  7. lrwx------ 1 vagrant vagrant 64 Nov 18 12:21 2 -> /dev/pts/1  
  8. lrwx------ 1 vagrant vagrant 64 Nov 18 12:21 3 -> socket:[2226056] 

上面列出的所有文件描述中,socket:[2226056]為 nc 命令監聽 8090 端口所創建的 socket。其中2226056為該 socket 的 inode。

根據該 inode 號,我們查看/proc/net/tcp對應的記錄信息,其中1F9A為本地端口號,轉換成十進制恰好為 8090: 

  1. vagrant@vagrant:/proc/25556/fd$ cat /proc/net/tcp | grep 2226056  
  2.    1: 00000000:1F9A 00000000:0000 0A 00000000:00000000 00:00000000 00000000  1000        0 2226056 1 0000000000000000 100 0 0 10 0 

根據進程 id,我們查看進程名稱和啟動參數: 

  1. vagrant@vagrant:/proc/25556/fd$ cat /proc/25556/cmdline  
  2. nc-l8090 

下面我們看下/proc/net/tcp文件格式。

/proc/net/tcp 文件格式

/proc/net/tcp文件首先會列出所有監聽狀態的 TCP 套接字,然后列出所有已建立的 TCP 套接字。我們通過head \-n 5 /proc/net/tcp命令查看該文件頭五行: 

  1. sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode  
  2.    0: 0100007F:0019 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 22279 1 0000000000000000 100 0 0 10 0  
  3.    1: 00000000:1FBB 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 21205 1 0000000000000000 100 0 0 10 0  
  4.    2: 00000000:26FB 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 21203 1 0000000000000000 100 0 0 10 0  
  5.    3: 00000000:26FD 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 21201 1 0000000000000000 100 0 0 10 0 

每一行各個字段解釋說明如下,由于太長分為三部分說明:

第一部分: 

  1. 46: 010310AC:9C4C 030310AC:1770 01   
  2. |      |      |      |      |   |--> 連接狀態,16 進制表示,具體值見下面說明  
  3. |      |      |      |      |------> 遠程 TCP 端口號,主機字節序,16 進制表示  
  4. |      |      |      |-------------> 遠程 IPv4 地址,網絡字節序,16 進制表示  
  5. |      |      |--------------------> 本地 TCP 端口號,主機字節序,16 進制表示  
  6. |      |---------------------------> 本地 IPv4 地址,網絡字節序,16 進制表示  
  7. |----------------------------------> 條目編號,從 0 開始 

上面連接狀態所有值如下,具體參見 linux 源碼 tcp\_states.h[1]: 

  1. enum {  
  2.  TCP_ESTABLISHED = 1 
  3.  TCP_SYN_SENT,  
  4.  TCP_SYN_RECV,  
  5.  TCP_FIN_WAIT1,  
  6.  TCP_FIN_WAIT2,  
  7.  TCP_TIME_WAIT,  
  8.  TCP_CLOSE,  
  9.  TCP_CLOSE_WAIT,  
  10.  TCP_LAST_ACK,  
  11.  TCP_LISTEN,  
  12.  TCP_CLOSING, /* Now a valid state */  
  13.  TCP_NEW_SYN_RECV,  
  14.  TCP_MAX_STATES /* Leave at the end! */  
  15. }; 

第二部分: 

  1. 00000150:00000000 01:00000019 00000000    
  2.       |        |     |     |       |--> number of unrecovered RTO timeouts  
  3.       |        |     |     |----------> number of jiffies until timer expires  
  4.       |        |     |----------------> timer_active,具體值見下面說明  
  5.       |        |----------------------> receive-queue,當狀態是 ESTABLISHED,表示接收隊列中數據長度;狀態是 LISTEN,表示已經完成連接隊列的長度  
  6.       |-------------------------------> transmit-queue,發送隊列中數據長度 

timer_active 所有值與說明如下:

  •  0 no timer is pending
  •  1 retransmit-timer is pending
  •  2 another timer (e.g. delayed ack or keepalive) is pending
  •  3 this is a socket in TIME_WAIT state. Not all fields will contain data (or even exist)
  •  4 zero window probe timer is pending

第三部分: 

  1. 1000        0 54165785 4 cd1e6040 25 4 27 3 -1  
  2.    |          |    |     |    |     |  | |  | |--> slow start size threshold,   
  3.    |          |    |     |    |     |  | |  |      or -1 if the threshold  
  4.    |          |    |     |    |     |  | |  |      is >= 0xFFFF  
  5.    |          |    |     |    |     |  | |  |----> sending congestion window  
  6.    |          |    |     |    |     |  | |-------> (ack.quick<<1)|ack.pingpong  
  7.    |          |    |     |    |     |  |---------> Predicted tick of soft clock  
  8.    |          |    |     |    |     |              (delayed ACK control data)  
  9.    |          |    |     |    |     |------------> retransmit timeout  
  10.    |          |    |     |    |------------------> location of socket in memory  
  11.    |          |    |     |-----------------------> socket reference count  
  12.    |          |    |-----------------------------> socket 的 inode 號  
  13.    |          |----------------------------------> unanswered 0-window probes 
  14.    |---------------------------------------------> socket 所屬用戶的 uid 

Go 實現簡易版本 netstat 命令

netstat 工作原理和/proc/net/tcp文件結構,我們都已經了解了,現在可以使用據此使用 Go 實現一個簡單版本的 netstat 命令。

核心代碼如下,完整代碼參加 go-netstat[2]: 

  1. // 狀態碼值  
  2. const (  
  3.  TCP_ESTABLISHED = iota + 1  
  4.  TCP_SYN_SENT  
  5.  TCP_SYN_RECV  
  6.  TCP_FIN_WAIT1  
  7.  TCP_FIN_WAIT2 
  8.  TCP_TIME_WAIT  
  9.  TCP_CLOSE  
  10.  TCP_CLOSE_WAIT  
  11.  TCP_LAST_ACK  
  12.  TCP_LISTEN  
  13.  TCP_CLOSING  
  14.  //TCP_NEW_SYN_RECV  
  15.  //TCP_MAX_STATES  
  16.  
  17. // 狀態碼  
  18. var states = map[int]string{  
  19.  TCP_ESTABLISHED: "ESTABLISHED",  
  20.  TCP_SYN_SENT:    "SYN_SENT",  
  21.  TCP_SYN_RECV:    "SYN_RECV",  
  22.  TCP_FIN_WAIT1:   "FIN_WAIT1",  
  23.  TCP_FIN_WAIT2:   "FIN_WAIT2",  
  24.  TCP_TIME_WAIT:   "TIME_WAIT",  
  25.  TCP_CLOSE:       "CLOSE",  
  26.  TCP_CLOSE_WAIT:  "CLOSE_WAIT",  
  27.  TCP_LAST_ACK:    "LAST_ACK",  
  28.  TCP_LISTEN:      "LISTEN",  
  29.  TCP_CLOSING:     "CLOSING",  
  30.  //TCP_NEW_SYN_RECV: "NEW_SYN_RECV",  
  31.  //TCP_MAX_STATES:   "MAX_STATES",  
  32.  
  33. // socketEntry 結構體,用來存儲/proc/net/tcp 每一行解析后數據信息  
  34. type socketEntry struct {  
  35.  id      int  
  36.  srcIP   net.IP  
  37.  srcPort int  
  38.  dstIP   net.IP  
  39.  dstPort int  
  40.  state   string  
  41.  txQueue       int  
  42.  rxQueue       int  
  43.  timer         int8  
  44.  timerDuration time.Duration  
  45.  rto           time.Duration // retransmission timeout  
  46.  uid           int  
  47.  uname         string  
  48.  timeout       time.Duration  
  49.  inode         string  
  50.  
  51. // 解析/proc/net/tcp 行記錄  
  52. func parseRawSocketEntry(entry string) (*socketEntry, error) {  
  53.  se := &socketEntry{} 
  54.  entrys :strings.Split(strings.TrimSpace(entry), " ")  
  55.  entryItems :make([]string, 0, 17)  
  56.  for _, ent :range entrys {  
  57.   if ent == "" {  
  58.    continue  
  59.   }  
  60.   entryItems = append(entryItems, ent)  
  61.  }  
  62.  id, err :strconv.Atoi(string(entryItems[0][:len(entryItems[0])-1]))  
  63.  if err != nil {  
  64.   return nil, err  
  65.  }  
  66.  se.id = id                                     // sockect entry id  
  67.  localAddr :strings.Split(entryItems[1], ":") // 本地 ip  
  68.  se.srcIP = parseHexBigEndianIPStr(localAddr[0])  
  69.  port, err :strconv.ParseInt(localAddr[1], 16, 32) // 本地 port  
  70.  if err != nil {  
  71.   return nil, err  
  72.  }  
  73.  se.srcPort = int(port)  
  74.  remoteAddr :strings.Split(entryItems[2], ":") // 遠程 ip  
  75.  se.dstIP = parseHexBigEndianIPStr(remoteAddr[0])  
  76.  port, err = strconv.ParseInt(remoteAddr[1], 16, 32) // 遠程 port  
  77.  if err != nil { 
  78.   return nil, err  
  79.  }  
  80.  se.dstPort = int(port)  
  81.  state, _ :strconv.ParseInt(entryItems[3], 16, 32) // socket 狀態  
  82.  se.state = states[int(state)] 
  83.  tcpQueue :strings.Split(entryItems[4], ":")  
  84.  tQueue, err :strconv.ParseInt(tcpQueue[0], 16, 32) // 發送隊列數據長度  
  85.  if err != nil {  
  86.   return nil, err  
  87.  }  
  88.  se.txQueue = int(tQueue)  
  89.  sQueue, err :strconv.ParseInt(tcpQueue[1], 16, 32) // 接收隊列數據長度  
  90.  if err != nil {  
  91.   return nil, err  
  92.  }  
  93.  se.rxQueue = int(sQueue)   
  94.  se.uid, err = strconv.Atoi(entryItems[7]) // socket uid  
  95.  if err != nil {  
  96.   return nil, err  
  97.  }  
  98.  se.uname = systemUsers[entryItems[7]] // socket user name 
  99.  se.inode = entryItems[9]              // socket inode  
  100.  return se, nil  
  101. // hexIP 是網絡字節序/大端法轉換成的 16 進制的字符串  
  102. func parseHexBigEndianIPStr(hexIP string) net.IP {  
  103.  b := []byte(hexIP)  
  104.  for i, j :1, len(b)-2; i < j; i, j = i+2, j-2 { // 反轉字節,轉換成小端法  
  105.   b[i], b[i-1], b[j], b[j+1] = b[j+1], b[j], b[i-1], b[i]  
  106.  }  
  107.  l, _ :strconv.ParseInt(string(b), 16, 64)  
  108.  return net.IPv4(byte(l>>24), byte(l>>16), byte(l>>8), byte(l))  
  109.  

 

責任編輯:龐桂玉 來源: 馬哥Linux運維
相關推薦

2023-12-29 08:31:49

Spring框架模塊

2022-11-01 18:29:25

Go語言排序算法

2020-08-12 08:56:30

代碼凱撒密碼函數

2023-05-08 07:55:05

快速排序Go 語言

2024-08-29 13:23:04

WindowsGo語言

2012-03-13 10:40:58

Google Go

2022-05-19 14:14:26

go語言限流算法

2022-02-11 13:44:56

fiber架構React

2012-08-06 08:50:05

Go語言

2024-06-06 09:47:56

2017-01-13 08:37:57

PythonAlphaGoMuGo

2023-07-31 08:01:13

二叉搜索測試

2021-07-26 09:47:38

Go語言C++

2023-03-27 00:20:48

2022-04-18 10:01:07

Go 語言漢諾塔游戲

2022-10-20 11:49:49

JS動畫幀,CSS

2011-12-05 10:37:53

Linux服務器Shell腳本

2021-03-01 21:59:25

編程語言GoCX

2021-03-01 18:35:18

Go語言虛擬機

2022-07-20 09:52:44

Go語言短信驗證碼
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 亚洲激情第一页 | 97精品久久 | 国产精品1区2区3区 欧美 中文字幕 | 久久精品久久久久久 | 男人天堂网址 | 国产欧美一区二区三区在线看 | 国产视频中文字幕 | 国产精品久久久久久久久久久久久 | 国产羞羞视频在线观看 | 涩涩视频在线观看 | 国产美女在线观看 | 一区二区在线免费观看 | 六月成人网| 天堂色 | 久久天天躁狠狠躁夜夜躁2014 | 国产精品久久7777777 | 久草青青 | 日韩一区二区福利视频 | 日韩欧美一级片 | 色婷婷精品久久二区二区蜜臂av | 91精品国产色综合久久不卡98口 | 亚洲精品1区 | 精品美女视频在免费观看 | 1区2区3区视频 | 久久国产精品视频免费看 | 欧美精品在线观看 | 久久y| 日韩欧美精品在线播放 | 国产探花在线精品一区二区 | 国产精品一区视频 | 国产亚洲欧美在线视频 | 精品国产欧美日韩不卡在线观看 | 亚洲成人激情在线观看 | 涩在线| 亚洲欧美日本国产 | h视频在线观看免费 | 国产激情视频 | 成人福利影院 | 国产99久久精品一区二区300 | 天天综合永久 | 精品国产乱码一区二区三区 |