SNMP項目有個需求,就是能夠動態改變net-snmp監聽的端口而不需要重啓設備。關於這個功能,一開始想的是如果端口變更了,那就直接使用pthread_kill 關閉原來的代理線程,然後重新執行線程。但是這樣子測試後發現重啓的線程會自動導致整個進程退出。
模塊框架大致是這樣,進程啓動讀取配置,然後創建一個獨立的代理線程,這個線程執行net-snmp庫的啓動入口(snmpd.c/SnmpDaemonMain)。
實測發現該接口不能夠重新執行,因爲第一次執行的時候庫裏面的很多靜態變量已經初始化,在進程內這些變量只會初始化一次,所以當後續的線程重新調用net-snmp庫的入口會初始化失敗。照這樣打算以多進程的方式來實現這個功能,畢竟進程的數據是獨立的。不過這樣開發的話進程之間的通信也是一個問題,想想這個複雜度還是算了。之前分析過庫的執行代碼,對庫的運行流程有了基本的瞭解,既然是重新監聽端口,那就將之前的端口關掉,重新執行以便就好了。
如上圖所示,打開監聽端口是在init_master_agent裏面,分析了裏面的函數調用,大致流程搞清楚後,在庫裏增加了幾個接口用於更新端口:
/* 相當於關閉之前的agent */
shutdown_master_agent()
/* 關閉執行的所有會話 */
snmp_close_sessions();
/* 重新執行下列步驟來刷新端口 */
/* 重新初始化庫內部使用的一個結構體 */
_init_agent_callback_transport();
/* 因爲snmp_close_sessions 關閉了所有會話,所以這裏要重新創建 */
if (agentx_callback_sess == NULL) {
agentx_callback_sess = netsnmp_callback_open(callback_master_num,
handle_subagent_response,
NULL, NULL);
DEBUGMSGTL(("agentx/subagent", "subagent_init sess %p\n",
agentx_callback_sess));
}
接下里重新調用正常的流程就可以了
init_master_agent()
如果有其它特殊的功能需要開發並且庫自身並不支持的話,可以多看看net-snmp源碼,嘗試修改就可以了。