環境準備:安裝 SNMP 服務
- 控制台 → 程式集 → 開啟或關閉 Windows 功能
- 勾選「簡單網路管理協定 (SNMP)」,需 Windows 安裝光碟/ISO
- 服務啟動:
net start snmp 或 services.msc 設為自動
- 防火牆開放 UDP 161 (查詢) 、UDP 162 (Trap)
開發環境:Platform SDK WinSNMP 範例
- 下載 Platform SDK (含 WinSNMP 樣本代碼)
- 樣本路徑:
PlatformSDK\Samples\NetMgmt\Snmp\Wsnmp
- 核心檔案:
wsnmputil.cpp, helper.cpp, Makefile
編譯步驟 (VC6.0 / VS.NET 2003 命令列)
> cd D:\Wsnmp
> nmake all
// 產生 WIN2000_DEBUG\wsnmputil.exe
WinSNMP API 核心流程
SnmpStartup:初始化 WinSNMP 工作階段
SnmpOpenSession:建立會話,指定目標 Agent IP/Community
SnmpStrToOid:將字串 OID (如 1.3.6.1.2.1.1.1.0) 轉內部結構
SnmpEncodeMsg / SnmpSendMsg:編碼並發送請求 (GET/GETNEXT/SET)
SnmpRecvMsg:接收回應
SnmpDecodeMsg / SnmpOidToStr / SnmpGetVb:解碼提取 VarBind 值
SnmpCloseSession / SnmpCleanup:釋放資源
最簡 GET 請求範例 (精簡自 wsnmputil.cpp)
#include
#include
#pragma comment(lib, "wsnmp32.lib")
void SnmpGet(LPSTR agentIp, LPSTR community, LPSTR oidStr) {
HSNMP_SESSION hSession;
HSNMP_ENTITY hSrcEntity, hDstEntity;
smiOID oid;
smiVALUE value;
SNMPAPI_STATUS status;
// 1. 啟動
if (SnmpStartup(&g_hWnd) != SNMPAPI_SUCCESS) return;
// 2. 開啟會話
hSrcEntity = SnmpStrToEntity(hSession, "local"); // 本機
hDstEntity = SnmpStrToEntity(hSession, agentIp); // 目標 Agent
hSession = SnmpOpenSession(hSrcEntity, hDstEntity, 0, 0); // 0=預設重試/超時
// 3. OID 轉換
SnmpStrToOid(oidStr, &oid);
// 4. 建構 VarBind List
smiVBL vbl = {0};
vbl.list = (smiVENDORINFO*)SnmpUtilMemAlloc(sizeof(smiVENDORINFO));
vbl.list[0].oid = oid;
vbl.list[0].value.syntax = SNMP_SYNTAX_NULL; // GET 請求值為 NULL
vbl.len = 1;
// 5. 發送 GET 請求
HSNMP_PDU hPdu = SnmpCreatePdu(hSession, SNMP_PDU_GET, 0, 0, &vbl);
SnmpSendMsg(hSession, hDstEntity, hSrcEntity, hPdu);
// 6. 接收回應 (同步阻塞)
HSNMP_PDU hRespPdu;
SnmpRecvMsg(hSession, &hSrcEntity, &hDstEntity, NULL, &hRespPdu);
// 7. 解析回應
smiVBL respVbl;
SnmpGetPduData(hRespPdu, NULL, NULL, NULL, NULL, &respVbl);
for (UINT i = 0; i < respVbl.len; ++i) {
char oidBuf[256];
SnmpOidToStr(&respVbl.list[i].oid, oidBuf);
char valBuf[256];
SnmpUtilVarBindToStr(&respVbl.list[i], valBuf, 256);
printf("OID: %s = %s\n", oidBuf, valBuf);
}
// 8. 清理
SnmpFreeEntity(hSrcEntity);
SnmpFreeEntity(hDstEntity);
SnmpCloseSession(hSession);
SnmpCleanup();
}
int main() {
SnmpGet("127.0.0.1", "public", "1.3.6.1.2.1.1.1.0"); // sysDescr
return 0;
}
常用標準 OID (MIB-II)
| OID | 名稱 | 說明 |
| 1.3.6.1.2.1.1.1.0 | sysDescr | 系統描述 |
| 1.3.6.1.2.1.1.3.0 | sysUpTime | 系統啟動時間 (百秒) |
| 1.3.6.1.2.1.1.5.0 | sysName | 主機名稱 |
| 1.3.6.1.2.1.2.2.1.2 | ifDescr | 介面描述 (表格,需 GETNEXT 遍歷) |
| 1.3.6.1.2.1.2.2.1.10 | ifInOctets | 介面接收位元組 |
| 1.3.6.1.2.1.2.2.1.16 | ifOutOctets | 介面發送位元組 |
| 1.3.6.1.2.1.25.2.3.1.3 | hrStorageDescr | 儲存裝置描述 (需 HOST-RESOURCES-MIB) |
進階:Trap 接收與 MIB 解析
- Trap 接收需註冊
SnmpRegister 回呼函數,監聽 UDP 162
- 企業級開發建議使用
Net-SNMP C 庫或 SNMP++ C++ 庫,支援 MIB 編譯、OID 名稱解析、SNMPv3 加密
- Windows 自帶
mgmtapi.dll 提供較高層封裝 (SnmpMgrRequest),但功能較 WinSNMP 受限
避坑指南
| 問題 | 解決 |
| SnmpStartup 失敗 | 確認 SNMP 服務已啟動、註冊表 HKLM\SYSTEM\CurrentControlSet\Services\SNMP\Parameters 正確 |
| Timeout 無回應 | 檢查防火牆 UDP 161、Community 字串正確 (預設 public)、Agent IP 可達 |
| OID 解析錯誤 | 使用 snmptranslate (Net-SNMP 工具) 驗證 OID 格式 |
| 64-bit 計數器溢位 | 使用 ifHCInOctets (1.3.6.1.2.1.31.1.1.1.6) 等 64-bit OID |
| 中文顯示亂碼 | 確保 SNMP Agent 回傳 UTF-8,客戶端用 MultiByteToWideChar(CP_UTF8) 轉換 |
總結
Windows 內建 WinSNMP API 提供輕量級 SNMP 客戶端開發能力,無需第三方庫即可完成基本 GET/GETNEXT/SET 操作。掌握 SnmpStartup → OpenSession → StrToOid → SendMsg → RecvMsg → Decode 核心流程,即可快速構建網管工具、監控代理或資產掃描器。