IPv4地址集合裡有兩個特殊地址:0.0.0.0、127.0.0.1,你是否了解他們的用途?輸入netstat -ano找到前面幾行有LISTEN标注的行,它表示本地系統開放的TCP4服務,文稿裡顯示本地已開放38127、111、37681等端口,這些端口外部都能訪問嗎?為什麼有些端口前面是0.0.0.0,有些卻是127.0.0.1呢?
如果你能輕易回答上面的問題,你已經不是網絡基礎小白,可以跳過這篇文章,單如果你不能,我想下面的工程實踐能給你解釋清楚。 另外你還能學到我的排查思路。
基本解釋
127.0.0.1叫 本地環回地址 ,用于測試協議棧的正确性,它不依賴硬件上是否有接網卡,它不依賴硬件上是否有接網卡,相當于用一根看不見的網線将網卡的發送和接收相連接起來。
0.0.0.0叫 任意地址 ,若某以太網設備存在多塊物理網卡,表示隻要本地開放對應的端口服務,無論從哪個網卡發起連接請求都是允許的。 若想限制某服務隻允許外部設備從指定網卡入口發起訪問,則配置成具體網卡的IP地址,就如文稿插圖箭頭那行,8081端口隻允許從IP地址為192.168.2.3的網卡入口發起。
在編寫IPv4 TCP應用程序時候,執行綁定(bind)地址和端口組成服務,下圖文稿INADDR_ANY參數最為常用,綁定“任意地址”。 本文接下來内容講述,當綁定地址非INADDR_ANY時會引起什麼現象、以及如何排查和解決。
真實場景排查
我前些天搭建MQTT平台mosquitto時遇到個問題: 服務器隻能向自己的環回地址 127.0.0.1地址發起連接,連接本地地址192.168.81.198則失敗。問題的原因就與缺省路由有關。
編譯好ARM平台下的mosquitto之後,我當然會在ARM上測試一服務是否正常,顯然是成功的,同樣我把測試程序拷貝到其它主機上運行,客戶端提示不可連接(Unable to connect),服務器界面也沒有任何異常信息打印。嵌入式工程師祖傳DNA有了反應: “It work on my machine” 。首先兩端都執行ping命令排查網絡連接狀态,排除防火牆、路由表的配置,都沒看出明顯異常。
接着我決定在服務器上再自己測試一次,隻不過這次換成本地網卡地址。
strace登場!沒抓到accept注釋掉客戶端之前環回地址代碼,修改HOST為本地網卡地址192.168.81.198,重新編譯執行。
// #define HOST "localhost"
// #define HOST "127.0.0.1"
#define HOST "192.168.81.198"
嘿~同樣提示Unable to connect,活久見,自己訪問自己的服務居然也會失敗! 莫非是權限不足被服務器拒絕導緻? 為探尋服務器究竟做了什麼,我用strace mosquitto重新啟動服務器,試圖抓取到應用程序執行軌迹, 屏幕有規律地滾動着epoll_wait信息,暗示服務器進入epoll循環。
在客戶端答應Unable to connect時strace沒抓取到服務器任何打破規律的系統調用,比如說TCP必須用到的accept。
為證明發生正常連接情況下,服務器會執行系統調用accept,我重新修改HOST為127.0.0.1後再次用strace抓取,果不其然看到accept的身影(你可在文稿圖标注的步驟4中看到它)。
由此可知,當向網卡地址192.168.81.198發起連接時,服務器應用程序根本沒收到協議棧的數據,接着我再打開Wireshark抓取TCP數據,探尋數據交互過程究竟發生了什麼。
Wirshark登場!RST、ACK
Wireshark默認截獲物理網卡數據,物理網卡是下圖的wlp3s0,雖然實驗向本地網卡地址192.168.81.198發起連接,而在實際上數據并沒有“經過物理網卡”,在協議棧裡路由選擇後切換成環回地址的路由。
Wireshark操作界面選擇抓取接口Loopback:lo。
對比客戶端分别向127.0.0.1和192.168.81.198發起連接的截獲情況。連接環回地址可成功完成三次握手( 對應序号21:SYN;22:SYN、ACK;23:ACK),向連接本地網卡連接卻被複位(對應序号15:SYNC;16:RST、ACK)。
複位連接的原因要麼是不存在此IP,要麼服務器沒啟動、此端口上不存在服務,要麼連接被防火牆過濾。鑒于前面已經排除防火牆可能,剩下的極有可能是本地服務器socket設置咯,輸入 “netstat -ano | grep 1883” 查看MQTT監聽端口狀态。
原因找到了,本地監聽地址是127.0.0.1:1883,而非0.0.0.0:1883,所以任何外部連接都被拒絕。
解決
怎麼處理呢?測試環境下mosquitto是不帶任何參數的,想必可以傳遞參數、配置文件靈活的更改mosquitto的特性。注意到另外一台x86平台Linux系統上已經搭建好mosquitto,ps -aux查看mosquitto的啟動參數, “mosquitto -c /etc/mosquitto/mosquitto.conf” 。x86平台下的mosquitto.conf文件内容短小且沒有任何注釋信息,也沒看到看似監聽配置的關鍵詞。
同目錄下還有另一個文件 mosquitto.conf.example ,他的内容要豐富得多,有詳細的介紹。
On systems that support Unix Domain Sockets, it is also possible to create a Unix socket rather than opening a TCP socket. In this case, the port number should be set to 0 and a unix socket path must be provided, e.g. listener 0 /tmp/mosquitto.sock
listener port-number [ip address/host name/unix socket path]
按照說明,重新編輯mosquitto.conf.example文件添加下面兩行,配置文件傳遞給服務器應用程序解析,netstat查詢到0.0.0.0:1883監聽,最後連接本地地址192.168.81.198成功。
# mosquitto.conf.example
listener 1883 0.0.0.0
allow_anonymous true
,
更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!