記錄一次大炮打蚊子的modbustcp通訊連線異常問題定位事件

乌拉Rua發表於2024-11-02

一.問題描述

某種場景下,安裝有Ubuntu22系統的裝置A開機後,1-2min內裝置E遙控器不能遙控裝置A移動,之後恢復正常。

二.裝置組網

記錄一次大炮打蚊子的modbustcp通訊連線異常問題定位事件

裝置A和裝置C之間使用modbustcp協議進行通訊。

三.首戰

3.1 檢視日誌

放開該埠的modbus查詢幀日誌列印,發現整體的幀格式,發現返回了modbus資料幀,但是返回幀是82錯誤碼的幀,可能是由網路問題導致的。

3.2 ping檢視網路通路通訊狀況

使用ping命令,ping從機ip,檢視是否能ping通,並檢視丟包率,確認通路良好,延遲低、無丟包。

3.3 mNetAssist網路除錯助手

在ubuntu主機上面安裝網路除錯助手mNetAssist,測試查詢資料正常。

3.3.1 使用方法

記錄一次大炮打蚊子的modbustcp通訊連線異常問題定位事件記錄一次大炮打蚊子的modbustcp通訊連線異常問題定位事件

在ubuntu上執行mNetAssist查詢從機資料:

  1. 協議型別選擇TCP客戶端;
  2. 伺服器IP和埠為指定的modbus從機的ip地址和埠;
  3. 本地IP填寫主機查詢網口的ip,本地埠隨便填寫會自動分配;
  4. 傳送設定要勾選按十六進位制傳送;
  5. 接收設定可以勾選顯示日期和按十六進位制顯示;

設定好之後,點選伺服器埠下方的連線網路,如果成功建立連線,會變為斷開網路,之後在本地IP下面填入要傳送的modbus資料幀,點選傳送,如果成功查詢到資料,上方的資料接收區會顯示查詢結果。

注意,1、2、3、4如果設定不正確,則可能無法建立網路連線,或者傳送查詢資料無反應。

3.3.2 安裝方法

透過百度網盤分享的檔案:網路除錯助手win_linux.zip

連結:https://pan.baidu.com/s/1MjVtxmtU4hTBV8wDKPN4_g

提取碼:t4nu

--來自百度網盤超級會員V8的分享

下載壓縮包,解壓後參考其中readme.txt中的操作。

3.4 使用wireshark抓包

Ubuntu主機安裝wireshark進行抓包,可以觀察到,確實在開機一段時間後才開始建立連線進行通訊。同時還注意到在開機之後一段時間內,有其他的ip在和從機建立連線,並且進入了retransmission階段,在該ip和從機重連結束後,目標主從機開始正常連線。

3.5 首戰總結分析

首戰,到此為止沒有什麼意外發現,也是在意料之中。

當前問題為開機1-2min內手柄無法遙控機器,開機之後,電腦連線路由器wifi需要一定時間,網路除錯助手和wireshark都是桌面端,連線wifi之後遠端桌面操作軟體更需要一定時間,現在可能需要徹底搞清楚從剛剛開機到連線成功之間的網路狀態。

因為是linux主機,所以可以考慮使用開機自啟動指令碼實現開機之後程式自啟動執行所需操作。

四.再戰

4.1 modbuspoll

上面我們安裝的mNetAssist網路除錯助手是桌面軟體,需要在介面手動修改各項引數,然後建立連線,進行查詢,不能應用於開機指令碼自啟動中,因此,我們需要找一款可以以命令列的方式工作的modbus資料幀查詢軟體,我選擇了modbuspoll。

  • ModbusPoll使用方法

mbpoll 192.168.11.12 -p 460 -B -0 -a 1 -t 1 -r 0 -c 0x10 -v

引數功能說明:

記錄一次大炮打蚊子的modbustcp通訊連線異常問題定位事件

4.2 tcpdump

因為wireshark也是圖形化介面操作,想要用指令碼在開機後自啟動抓包,就需要一款命令列操作的抓包工具,我選擇了tcpdump。

直接抓取所有介面的流量:sudo tcpdump -i any -w capture.pcap

4.3開機自啟動實現方式

4.3.1方式一.應用程式級啟動方式

以tcpdump自啟動指令碼為例:

1.首先來寫一個抓取資料包的指令碼tcpdump_self_start_cap.sh:

#!/bin/bash

current_time=$(date +"%Y%m%d-%H%M%S")

echo "password" | sudo -S tcpdump -i any -w capture_${current_time}.pcap

注:

password:為執行sudo命令時需要輸入的密碼

-S: 想要sudo命令從管道中讀取echo輸入的密碼,必須加這個引數

2.在Activities → start application → Add → Command中輸入:

gnome-terminal -x bash -c "/....../tcpdump_self_start_cap.sh"

3.最終效果

該方法實現的開機自啟動指令碼,linux開機啟動後,遠端桌面登入linux系統,就會開啟一個終端,並自動執行指令碼程式,但是如果開機啟動後不遠端連線桌面,該指令碼就一直不會自啟動,顯然這種方式並不是真正的開機自啟動,也無法達到我想要的效果。

4.3.2方式二.系統級啟動方式

同樣以tcpdump為例,tcpdump執行指令碼還是上面的指令碼tcpdump_self_start_cap.sh。

1.在/etc/systemd/system路徑下新增tcpdump_capture.service指令碼,指令碼內容如下:

[Unit]

Description=Capture network traffic using tcpdump

After=network.target

[Service]

User=root

ExecStart=/....../tcpdump_self_start_cap.sh

Restart=always

[Install]

WantedBy=multi-user.target

2.執行如下命令

sudo systemctl enable tcpdump_capture.service

sudo systemctl start tcpdump_capture.service

3.執行效果

系統開機後,不需要連線linux主機,就會自動啟動指令碼執行相應操作

4.4 再戰總結分析

將tcpdump抓包和modbuspoll資料幀查詢指令碼均加入開機自啟動服務,復現問題場景,觀察到,開機啟動後短時間內modbuspoll就可以和從機通訊,1-2min後問題軟體才開始和modbus從機通訊。

dmesg、syslog和journalctl日誌也未發現網路異常,經過兩次測試驗證,可以確認問題程式之外的其他方面應該沒有問題,因此重新回到問題程式,推測是程式的什麼地方耗費了較長的時間。

五.終戰

5.1 迴歸日誌和問題程式

回看之前儲存的問題情況下的日誌,仔細觀察後發現:

記錄一次大炮打蚊子的modbustcp通訊連線異常問題定位事件

tcp初始化之後一直到tcp成功連線,中間居然隔了133s,其中主要時間都浪費在了初始化和第一次連線之間:

記錄一次大炮打蚊子的modbustcp通訊連線異常問題定位事件

回看程式碼,發現初始化到建立連線之間並沒有什麼耗時的操作,大膽推測是建立連線的過程比較耗時,於是在connect函式執行前後新增日誌列印:

...”...before connect...”...;

sc_ -> connect(...);

...”...after connect...”...;

復現問題場景之後,可以看到:

記錄一次大炮打蚊子的modbustcp通訊連線異常問題定位事件

目前想到的解決辦法是呼叫非同步async_connect函式建立連線,結合deadline_timer增加超時時間,是否能解決當前問題尚未測試驗證

5.2 終戰總結分析

1.看日誌還是要認真仔細一點;

2.學習別人的原始碼還是要細節一點;

PS:希望這篇記錄能對大家在使用文中提及的工具上有所幫助,更深的幫助應該是沒有了。

相關文章