大家好這裡是費了很多神的小編過路君子
趁著設備換新,一咬牙把一年半前的程式整個大改,改成小編看起來比較舒服的形式。
在約一年半之前,小編大約是使用 java 直接去呼叫 Linux 的 system call,換句話說基本上就是整套程式裸奔在系統內,整體的遷移性非常差。
轉眼間就過了一年半,原本的伺服器被更新、更強的伺服器取代了,而小編也主動將這兩支程式切開在不同的主機上,意思就是原本的方法不可以使用了。
那不瞞各位,一年半前也正是小編剛開始學習 Linux,對整套 Linux 怎麼運行還非常生疏,想想當初小編自己想出 syscall 的方式時還沾沾自喜,現在回頭去看,這到底是什麼爛方法!
那這邊就簡單的用一張規格表來開場吧:
程式語言 | 作業系統 | 角色 |
Python3 | Ubuntu | 客戶端 |
Shell | CentOS 7.9.2009 | 伺服器端 |
Shell
我們先來看看 Shell 這邊該如何啟動一個 socket。
那我們是使用 nc 這個套件來啟動 socket,而 nc 套件在 CentOS 7 的最小安裝下是沒有的,所以如果伺服器內沒有 nc 可以先下:
sudo yum install -y nc
然後就可以開始構築我們的 Linux shell 程式碼了。
既然 Shell 作為我們的伺服器端,那勢必得接受來自外部或是內部的連線請求,故相關的 IP 以及防火牆的設定需要另外去調整。
如果防火牆是使用 firewall,那防火牆設定指令可以參考小編這篇:【CentOS 8】 防火牆基本操作@小編過路君子
# 持續監聽埠 while true do socketPID="" # 啟動 socket 並將其放到背景執行 # 並且會在 50000 埠持續 listening # 使用 TCP 來連線 # 若要使用 UDP 只需要加上 -u 即可 coproc SOCKET { nc -l 0.0.0.0 50000; } # 開始讀取 socket 收到的訊息 # 要回覆客戶端,只需要將訊息放入 echo 即可 while read cmd do if [ "${cmd}" = "stop" ]; then echo "DONE" break elif [ "${cmd}" = "hello" ]; then echo "world" else echo "none" fi done <&"${SOCKET[0]}" >&"${SOCKET[1]}" # 殺掉此 socket # 避免埠被占用造成再次啟動失敗 kill "${socketPID}" done
那至於為什麼使用 echo 就可以將訊息回覆給客戶端,其實跟 coproc 和 ${SOCKET} 有關,這邊小編就不展開來講了。
相關概念為 Linux 的 pipe 指令和 Linux coproc 指令,有興趣的人可以自行搜尋相關資料。
Python3
由於 python3 作為客戶端,只要能跟我們的伺服器取得連線即可,防火牆或 IP 隨便。
不同於 shell,Python3 本身就已經內建了 socket 操作相關的函數,我們只需要直接 import 進來即可。
from socket import socket, AF_INET, SOCK_STREAM class inServer(): def connect(self): # 創建 socket 並使用 TCP 來連線 console = socket(AF_INET, SOCK_STREAM) # 連線到遠端伺服器 console.connect(("REMOTE_SERVER_IP", 5000)) # 發送訊息到遠端伺服器 console.send("hello\n".encode("utf-8")) # 等待伺服器回覆並解析該訊息 msg = console.recv(1024).decode("utf-8") if msg == "world\n": console.send("stop\n".encode("utf-8")) # 關閉 socket console.close() client = inServer() client.connect()
大致上就這樣,非常簡單的連線範例,那其中最令人討厭的就是 \n,各位可以仔細觀察 Python3 發送的字串,以及 Shell 實際比對的字串,反之亦然。
基本上這是小編慢慢的經過好幾個小時一次又一次的測試,才終於抓出他們傳送以及比對字串的邏輯。
後記
本來小編一開始打算使用 web server 來撰寫此功能,但是後來想了想,沒必要為了幾個字串就使用 web server 這麼強大的功能,所以後來又轉向 net。
同樣的理由,所以最後選擇使用更底層的 socket 來傳遞訊息就好,這樣連 header 都省了,但是還是可以保持訊息的正確性。