用GO實現(xiàn)IP門禁優(yōu)化網(wǎng)絡(luò)流量管理
背景
最近在處理數(shù)據(jù)時,發(fā)現(xiàn)線上某個接口的訪問量異常高。在初次設(shè)計時,并未對流量和訪問量進行限制,因此對具體情況并不太清楚。為了解決這一問題,搞了一個簡單的IP過濾腳本,并進行了記錄。
之前搞IP過濾的時候, 使用了 PHP 的 workerman 來搞的 其實思路差不多一樣:
$worker = new Worker('tcp:0.0.0.0:8080'); // 監(jiān)聽一個端口 $worker->count = 2; // 設(shè)置多進程 $worker->onConnect = function (TcpConnection $connection) { $list_ip = []; // ip 白名單 $remote_ip = $connection->getRemoteIp(); // 攔截IP if (!in_array($remote_ip, $list_ip)) { $connection->close(); } // 放行連接,連接內(nèi)部目標(biāo)端口 $to_connection = new AsyncTcpConnection('tcp:127.0.0.1:80'); // 互相轉(zhuǎn)發(fā)流量 $connection->pipe($to_connection); $to_connection->pipe($connection); $to_connection->connect(); }
以上PHP代碼創(chuàng)建了一個TCP監(jiān)聽器,在連接時進行IP過濾,并將流量轉(zhuǎn)發(fā)到目標(biāo)端口。
Go實現(xiàn)客戶端
func main() { listener, err := net.Listen("tcp", "127.0.0.1:8080") if err != nil { fmt.Println("Listen() failed, err: ", err) return } defer func(listener net.Listener) { _ = listener.Close() }(listener) for { conn, err := listener.Accept() if err != nil { fmt.Println("Accept() failed, err: ", err) continue } ip, _, _ := net.SplitHostPort(conn.RemoteAddr().String()) if !isIPAllowed(ip) { fmt.Println("IP: ", ip, " is not allowed") _ = conn.Close() // TODO 對非白名單IP的連接,應(yīng)該進行一些處理,比如記錄日志 continue } fmt.Println("IP: ", ip, " is allowed") go handleConn(conn) // 轉(zhuǎn)發(fā)到固定的目標(biāo)端口 } } func handleConn(conn net.Conn) { defer func(conn net.Conn) { _ = conn.Close() }(conn) target, err := net.Dial("tcp", "127.0.0.1:80") if err != nil { fmt.Println("Dial() failed, err: ", err) return } defer func(target net.Conn) { _ = target.Close() }(target) // 使用 copyAndCount 的并發(fā)執(zhí)行版本(同時處理流向) go copyAndCount(target, conn, &inTraffic) copyAndCount(conn, target, &outTraffic) // Block until this copy is done }
代碼流程
啟動一個 TCP 監(jiān)聽器,等待客戶端的連接請求。
當(dāng)收到連接請求時,檢查連接的 IP 是否在白名單中。
如果 IP 在白名單中,則開始處理連接,將連接的流量從輸入流量和輸出流量分別計入相應(yīng)的計數(shù)器中。
處理連接時,使用 copyAndCount 函數(shù)并發(fā)地處理兩個方向的流量。
處理完成后,關(guān)閉連接。
循環(huán)等待新的連接請求。
Go 實現(xiàn)管理面板
剛開始準備寫這個IP過濾的時候,沒有考慮太多,直接就寫了,后來發(fā)現(xiàn),這個東西,其實可以寫一個管理面板,這樣就方便管理了. 然后就 使用 Gin 來整了個面板
主要功能如下:
IP 白名單管理, 并且提供了一個接口, 給上面的 轉(zhuǎn)發(fā)客戶端來用
攔截統(tǒng)計,提供了一個接口, 給上面的客戶端來上報攔截日志
流量統(tǒng)計, 包括輸入流量和輸出流量
流量限制, 包括輸入流量限制和輸出流量限制
后續(xù)完善
目前這個腳本只支持了一個端口的轉(zhuǎn)發(fā),沒有實現(xiàn)多個端口的同時綁定轉(zhuǎn)發(fā)
目前這個腳本沒有實現(xiàn)對客戶端的流量進行限制, 也沒有實現(xiàn)對服務(wù)器的流量進行限制
總結(jié)
最后的最后,我也不知道我這玩意兒該叫啥, 因為, 其實, 它就是一個轉(zhuǎn)發(fā)代理, 只不過, 它對流量進行了限制, 并且對流量進行了統(tǒng)計, 并且提供了管理面板.
以上就是用GO實現(xiàn)IP門禁優(yōu)化網(wǎng)絡(luò)流量管理的詳細內(nèi)容,更多關(guān)于GO IP門禁的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Golang 處理浮點數(shù)遇到的精度問題(使用decimal)
本文主要介紹了Golang 處理浮點數(shù)遇到的精度問題,不使用decimal會出大問題,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-02-02