精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

探究Go語言如何實現簡易版netstat命令

阿銘linux ? 來源:杰哥的IT之旅 ? 作者: 杰哥的IT之旅 ? 2021-07-27 10:35 ? 次閱讀

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

netstat 工作原理

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

17f98660-e3ff-11eb-a97a-12bb97331649.jpg

netstat 工作原理如下:

通過讀取/proc/net/tcp 、/proc/net/tcp6 文件,獲取 socket 本地地址,本地端口,遠程地址,遠程端口,狀態,inode 等信息

接著掃描所有/proc/[pid]/fd 目錄下的的 socket 文件描述符,建立 inode 到進程 pid 映射

根據 pid 讀取/proc/[pid]/cmdline 文件,獲取進程命令和啟動參數

根據 2,3 步驟,即可以獲得 1 中對應 socket 的相關進程信息

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

nc -l 8090

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

vagrant@vagrant:/proc/25556/fd$ ls -alh

total 0

dr-x------ 2 vagrant vagrant 0 Nov 18 12:21 。

dr-xr-xr-x 9 vagrant vagrant 0 Nov 18 12:20 。。

lrwx------ 1 vagrant vagrant 64 Nov 18 12:21 0 -》 /dev/pts/1

lrwx------ 1 vagrant vagrant 64 Nov 18 12:21 1 -》 /dev/pts/1

lrwx------ 1 vagrant vagrant 64 Nov 18 12:21 2 -》 /dev/pts/1

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:

vagrant@vagrant:/proc/25556/fd$ cat /proc/net/tcp | grep 2226056

1: 00000000:1F9A 00000000:0000 0A 00000000:00000000 00:00000000 00000000 1000 0 2226056 1 0000000000000000 100 0 0 10 0

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

vagrant@vagrant:/proc/25556/fd$ cat /proc/25556/cmdline

nc-l8090

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

/proc/net/tcp 文件格式

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

sl local_address rem_address st tx_queue rx_queue tr tm-》when retrnsmt uid timeout inode

0: 0100007F:0019 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 22279 1 0000000000000000 100 0 0 10 0

1: 00000000:1FBB 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 21205 1 0000000000000000 100 0 0 10 0

2: 00000000:26FB 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 21203 1 0000000000000000 100 0 0 10 0

3: 00000000:26FD 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 21201 1 0000000000000000 100 0 0 10 0

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

第一部分:

46: 010310AC:9C4C 030310AC:1770 01

| | | | | |--》 連接狀態,16 進制表示,具體值見下面說明

| | | | |------》 遠程 TCP 端口號,主機字節序,16 進制表示

| | | |-------------》 遠程 IPv4 地址,網絡字節序,16 進制表示

| | |--------------------》 本地 TCP 端口號,主機字節序,16 進制表示

| |---------------------------》 本地 IPv4 地址,網絡字節序,16 進制表示

|----------------------------------》 條目編號,從 0 開始

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

enum {

TCP_ESTABLISHED = 1,

TCP_SYN_SENT,

TCP_SYN_RECV,

TCP_FIN_WAIT1,

TCP_FIN_WAIT2,

TCP_TIME_WAIT,

TCP_CLOSE,

TCP_CLOSE_WAIT,

TCP_LAST_ACK,

TCP_LISTEN,

TCP_CLOSING, /* Now a valid state */

TCP_NEW_SYN_RECV,

TCP_MAX_STATES /* Leave at the end! */

};

第二部分:

00000150:00000000 01:00000019 00000000

| | | | |--》 number of unrecovered RTO timeouts

| | | |----------》 number of jiffies until timer expires

| | |----------------》 timer_active,具體值見下面說明

| |----------------------》 receive-queue,當狀態是 ESTABLISHED,表示接收隊列中數據長度;狀態是 LISTEN,表示已經完成連接隊列的長度

|-------------------------------》 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

第三部分:

1000 0 54165785 4 cd1e6040 25 4 27 3 -1

| | | | | | | | | |--》 slow start size threshold,

| | | | | | | | | or -1 if the threshold

| | | | | | | | | is 》= 0xFFFF

| | | | | | | | |----》 sending congestion window

| | | | | | | |-------》 (ack.quick《《1)|ack.pingpong

| | | | | | |---------》 Predicted tick of soft clock

| | | | | | (delayed ACK control data)

| | | | | |------------》 retransmit timeout

| | | | |------------------》 location of socket in memory

| | | |-----------------------》 socket reference count

| | |-----------------------------》 socket 的 inode 號

| |----------------------------------》 unanswered 0-window probes

|---------------------------------------------》 socket 所屬用戶的 uid

Go 實現簡易版本 netstat 命令

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

18041148-e3ff-11eb-a97a-12bb97331649.jpg

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

// 狀態碼值const (

TCP_ESTABLISHED = iota + 1

TCP_SYN_SENT

TCP_SYN_RECV

TCP_FIN_WAIT1

TCP_FIN_WAIT2

TCP_TIME_WAIT

TCP_CLOSE

TCP_CLOSE_WAIT

TCP_LAST_ACK

TCP_LISTEN

TCP_CLOSING

//TCP_NEW_SYN_RECV

//TCP_MAX_STATES

// 狀態碼var states = map[int]string{

TCP_ESTABLISHED: “ESTABLISHED”,

TCP_SYN_SENT: “SYN_SENT”,

TCP_SYN_RECV: “SYN_RECV”,

TCP_FIN_WAIT1: “FIN_WAIT1”,

TCP_FIN_WAIT2: “FIN_WAIT2”,

TCP_TIME_WAIT: “TIME_WAIT”,

TCP_CLOSE: “CLOSE”,

TCP_CLOSE_WAIT: “CLOSE_WAIT”,

TCP_LAST_ACK: “LAST_ACK”,

TCP_LISTEN: “LISTEN”,

TCP_CLOSING: “CLOSING”,

//TCP_NEW_SYN_RECV: “NEW_SYN_RECV”,

//TCP_MAX_STATES: “MAX_STATES”,

}

// socketEntry 結構體,用來存儲/proc/net/tcp 每一行解析后數據信息type socketEntry struct {

id int

srcIP net.IP

srcPort int

dstIP net.IP

dstPort int

state string

txQueue int

rxQueue int

timer int8

timerDuration time.Duration

rto time.Duration // retransmission timeout

uid int

uname string

timeout time.Duration

inode string

}

// 解析/proc/net/tcp 行記錄func parseRawSocketEntry(entry string) (*socketEntry, error) {

se := &socketEntry{}

entrys := strings.Split(strings.TrimSpace(entry), “ ”)

entryItems := make([]string, 0, 17)

for _, ent := range entrys {

if ent == “” {

continue

}

entryItems = append(entryItems, ent)

}

id, err := strconv.Atoi(string(entryItems[0][:len(entryItems[0])-1]))

if err != nil {

return nil, err

}

se.id = id // sockect entry id

localAddr := strings.Split(entryItems[1], “:”) // 本地 ip

se.srcIP = parseHexBigEndianIPStr(localAddr[0])

port, err := strconv.ParseInt(localAddr[1], 16, 32) // 本地 port

if err != nil {

return nil, err

}

se.srcPort = int(port)

remoteAddr := strings.Split(entryItems[2], “:”) // 遠程 ip

se.dstIP = parseHexBigEndianIPStr(remoteAddr[0])

port, err = strconv.ParseInt(remoteAddr[1], 16, 32) // 遠程 port

if err != nil {

return nil, err

}

se.dstPort = int(port)

state, _ := strconv.ParseInt(entryItems[3], 16, 32) // socket 狀態

se.state = states[int(state)]

tcpQueue := strings.Split(entryItems[4], “:”)

tQueue, err := strconv.ParseInt(tcpQueue[0], 16, 32) // 發送隊列數據長度

if err != nil {

return nil, err

}

se.txQueue = int(tQueue)

sQueue, err := strconv.ParseInt(tcpQueue[1], 16, 32) // 接收隊列數據長度

if err != nil {

return nil, err

}

se.rxQueue = int(sQueue)

se.uid, err = strconv.Atoi(entryItems[7]) // socket uid

if err != nil {

return nil, err

}

se.uname = systemUsers[entryItems[7]] // socket user name

se.inode = entryItems[9] // socket inode

return se, nil

}

// hexIP 是網絡字節序/大端法轉換成的 16 進制的字符串func parseHexBigEndianIPStr(hexIP string) net.IP {

b := []byte(hexIP)

for i, j := 1, len(b)-2; i 《 j; i, j = i+2, j-2 { // 反轉字節,轉換成小端法

b[i], b[i-1], b[j], b[j+1] = b[j+1], b[j], b[i-1], b[i]

}

l, _ := strconv.ParseInt(string(b), 16, 64)

return net.IPv4(byte(l》》24), byte(l》》16), byte(l》》8), byte(l))

}

編輯:jq

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • Linux
    +關注

    關注

    87

    文章

    11232

    瀏覽量

    208952

原文標題:Go 語言實現簡易版 netstat 命令

文章出處:【微信號:aming_linux,微信公眾號:阿銘linux】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    在學習go語言的過程踩過的坑

    作為一個5年的phper,這兩年公司和個人都在順應技術趨勢,新項目慢慢從php轉向了go語言,從2021年到現在,筆者手上也先后開發了兩個go項目。在學習go
    的頭像 發表于 11-11 09:22 ?114次閱讀

    go語言如何解決并發問題

    作為一個后端開發,日常工作中接觸最多的兩門語言就是PHP和GO了。無可否認,PHP確實是最好的語言(手動狗頭哈哈),寫起來真的很舒爽,沒有任何心智負擔,字符串和整型壓根就不用區分,開發速度真的是比
    的頭像 發表于 10-23 13:38 ?113次閱讀
    <b class='flag-5'>go</b><b class='flag-5'>語言</b>如何解決并發問題

    verilog設計之基于basys3實現簡易分秒數字鐘

    基于basys3實現簡易分秒數字鐘
    發表于 09-03 14:15 ?0次下載

    三十分鐘入門基礎Go Java小子版

    前言 Go語言定義 Go(又稱 Golang)是 Google 的 Robert Griesemer,Rob Pike 及 Ken Thompson 開發的一種靜態、強類型、編譯型語言
    的頭像 發表于 08-12 14:32 ?683次閱讀
    三十分鐘入門基礎<b class='flag-5'>Go</b> Java小子版

    用ESP32,做了個siri?!開源了!

    觸碰交互3.通過修改代碼,可以設置AI的對話方式和回答風格4.支持用于拓展設計,例如:智能MP3、簡易版siri/小愛同學、實時翻譯工具…想實現這些功能,軟硬件如
    的頭像 發表于 06-29 08:04 ?328次閱讀
    用ESP32,做了個siri?!開源了!

    AWTK 開源串口屏開發(18) - 用 C 語言自定義命令

    編寫代碼即可實現常見的應用。但是,有時候我們需要自定義一些命令,以實現一些特殊的功能。本文檔介紹如何使用C語言自定義命令。1.
    的頭像 發表于 05-11 08:24 ?421次閱讀
    AWTK 開源串口屏開發(18) - 用 C <b class='flag-5'>語言</b>自定義<b class='flag-5'>命令</b>

    關于go中接口類型的表示方法

    go是一個靜態性語言,每個變量都有靜態的類型,因此每個變量在編譯階段中有明確的變量類型,比如像:int、float32、MyType。
    的頭像 發表于 04-28 10:13 ?337次閱讀

    物聯網中常用指令——AT命令

    AT 命令是一種短文本命令語言,其歷史可以追溯到 1981 年,最初是為 Hayes 智能調制解調器開發的,后來在 20 世紀 90 年代用于撥號調制解調器。
    發表于 04-26 17:35 ?5420次閱讀
    物聯網中常用指令——AT<b class='flag-5'>命令</b>

    Go語言中的函數、方法與接口詳解

    Go 沒有類,不過可以為結構體類型定義方法。方法就是一類帶特殊的接收者參數的函數。方法接收者在它自己的參數列表內,位于 func 關鍵字和方法名之間。(非結構體類型也可以定義方法)
    的頭像 發表于 04-23 16:21 ?756次閱讀

    學習筆記|如何用Go程序采集溫濕度傳感器數據

    整個利用Go語言從AHT20溫濕度傳感器獲取數據的完整步驟和實現方法。一、C程序獲取AHT20溫濕度1、參考ElfBoard官方例程:03-例程源碼\03-1命令
    的頭像 發表于 03-21 11:46 ?649次閱讀
    學習筆記|如何用<b class='flag-5'>Go</b>程序采集溫濕度傳感器數據

    使用go語言實現一個grpc攔截器

    在開發grpc服務時,我們經常會遇到一些通用的需求,比如:日志、鏈路追蹤、鑒權等。這些需求可以通過grpc攔截器來實現。本文使用go語言實現一個 grpc一元模式(Unary)攔截器
    的頭像 發表于 12-18 10:13 ?638次閱讀
    使用<b class='flag-5'>go</b><b class='flag-5'>語言實現</b>一個grpc攔截器

    Go編程語言-你應該知道的一切

    Go 編程語言的故事始于 Google,當時三位工程師 Robert Griesemer、Rob Pike 和 Ken Thompson 對 C++ 的復雜性以及缺乏提供高效編譯和執行的簡單語言感到厭倦。
    的頭像 發表于 12-11 17:37 ?620次閱讀

    idea如何輸入命令行參數

    在許多軟件開發和系統管理的任務中,我們經常需要向應用程序傳遞命令行參數。命令行參數是在運行時傳遞給程序的值,用于指定程序的行為和配置選項。本文將詳細介紹如何在不同的編程語言和操作系統中輸入命令
    的頭像 發表于 12-06 15:01 ?1092次閱讀

    uboot命令的執行過程是什么

    u-boot命令的執行過程。 1、u-boot命令的執行過程 在u-boot命令執行到最后時,開始進入命令循環,等待用戶輸入命令和處理
    的頭像 發表于 12-04 17:31 ?774次閱讀

    Uboot命令實現大致流程圖

    zImage內核鏡像下載到開發板之后,可以使用u-boot的go命令進行直接跳轉,這個時候內核直接解壓啟動。 但是此時的內核無法掛載文件系統,因為go命令沒有將內核需要的相關啟動參數從
    的頭像 發表于 12-04 17:09 ?395次閱讀
    Uboot<b class='flag-5'>命令</b><b class='flag-5'>實現</b>大致流程圖