SNMP上手攻略
版本:1.0工作中需要用到SNMP的开发,于是马上利用各种资源,图书馆、图书城、因特网来急寻各种相关资料。SNMP是简单网络管理协议的英文缩写,可以用来做网络管理。虽然这方面的资料不像C++等技术的资料那么泛滥(对于当今C++领域的出版状况,我情愿用泛滥而不想用丰富,跑题了,^_^),但是也不是乏善可陈。在CSDN、google上搜索SNMP。一下子就是一大堆。可是通通是(也许是我找得不够仔细)讲诸如SNMP历史、SNMP是什么、SNMP与其他协议比较的优劣等等。毋庸置疑这样的文章对于像我这样从来没有听说过SNMP的菜鸟是雪中炭。可是欢乐是短暂的,在了解完概念之后想去做一个类似Hello World 一样的程序看看的时候。确怎么也无法找到一个可以方便运行的Demo。
因此本文不再介绍SNMP的概念,而是一步步教你怎么实现一个SNMP程序的“Hello World”。关于概念《SNMP网络管理》 William Stallings 著。 中国电力出版 一书中有比较详细的介绍。可是让我受不了的是整本书几乎没有一句代码,也许这本书本身就不是给程序员看得,而且书的翻译也给人感觉就像路边的大排档。
二. 准备工作我用的是 Win2k Professionnal + SP4 中文版,其他平台我实在是没有时间试验了,不过应该大同小异。
2.1 安装SNMP agent首先得保证自己机器上有SNMP这个服务。安装的地方在“网络和拨号链接”窗体里面,可以通过在桌面上右键点击“网上邻居->属性”得到。
在网络和拨号链接窗体里面选择“高级->可选网络组件”菜单出现如下对话框:
在这个对话框中要保证“管理和监视工具”是被选择的,SNMP的相关组件就在这个选项里面,而这个选择缺省Windows安装是不安装的。如果你的机器还没有安装,那么选择上吧。
2.2 例子程序自己写一个例子程序似乎不可行,如果您已经能自己写一个SNMP程序了,那么这篇文章就不要看了吧。我们直接用一个MSDN上的例子吧。在VS6的Msdn上有这么一个例子在...\Samples\VC98\SDK\NETDS\SNMP\SNMPUTIL下面。有意思的是这个例子的Readme里面也没有讲运行的时候需要什么条件。可以理解的原因是这种程序不是用在本机PC上的,而是控制路由器等远程网络设备的。
虽然相信很多地方都可以找到这个程序,但是我还是把它的代码贴到这里,一来显得文章有了“份量”。二来为了给少数机器上没有装全msdn的人一个方便。三来这个代码我稍微做了一点修改,在出错的时候打印出了出错原因的字符描述,原来的例子给出的是整数的代码。让人不能直观地知道是什么原因。
这个例子是console程序,没有任何窗体、对话框。而且就一个.C文件,也很方便贴出来。另外还有一个MAKEFILE文件,这里就不列出了。
以下是SNMPUTIL.C文件:
/*++ BUILD Version: 0001 // Increment this if a change has global effects Copyright (c) 1991-1995 Microsoft Corporation Module Name: snmputil.c Abstract: Sample SNMP Management API usage for Windows NT. This file is an example of how to code management applications using the SNMP Management API for Windows NT. It is similar in operation to the other commonly available SNMP command line utilities. Extensive comments have been included to describe its structure and operation. See also "Microsoft Windows/NT SNMP Programmer's Reference". Created: 28-Jun-1991 Revision History: --*/ static char *vcsid = "@(#) $Logfile: N:/agent/mgmtapi/vcs/snmputil.c_v $ $Revision: 1.5 $"; // General notes: // Microsoft's SNMP Management API for Windows NT is implemented as a DLL // that is linked with the developer's code. These APIs (examples follow in // this file) allow the developer's code to generate SNMP queries and receive // SNMP traps. A simple MIB compiler and related APIs are also available to // allow conversions between OBJECT IDENTIFIERS and OBJECT DESCRIPTORS. // Necessary includes. #include <windows.h> #include <stdio.h> #include <string.h> #include <malloc.h> #include <snmp.h> #include <mgmtapi.h> // Constants used in this example. #define GET 1 #define GETNEXT 2 #define WALK 3 #define TRAP 4 #define TIMEOUT 6000 /* milliseconds */ #define RETRIES 3 // Main program. INT _CRTAPI1 main( IN int argumentCount, IN char *argumentVector[]) { INT operation; LPSTR agent; LPSTR community; RFC1157VarBindList variableBindings; LPSNMP_MGR_SESSION session; INT timeout = TIMEOUT; INT retries = RETRIES; BYTE requestType; AsnInteger errorStatus; AsnInteger errorIndex; char *chkPtr = NULL; // Parse command line arguments to determine requested operation. // Verify number of arguments... if (argumentCount < 5 && argumentCount != 2) { printf("Error: Incorrect number of arguments specified.\n"); printf( "\nusage: snmputil [get|getnext|walk] agent community oid [oid ...]\n"); printf( " snmputil trap\n"); return 1; } // Get/verify operation... argumentVector++; argumentCount--; if (!strcmp(*argumentVector, "get")) operation = GET; else if (!strcmp(*argumentVector, "getnext")) operation = GETNEXT; else if (!strcmp(*argumentVector, "walk")) operation = WALK; else if (!strcmp(*argumentVector, "trap")) operation = TRAP; else { printf("Error: Invalid operation, '%s', specified.\n", *argumentVector); return 1; } if (operation != TRAP) { if (argumentCount < 4) { printf("Error: Incorrect number of arguments specified.\n"); printf( "\nusage: snmputil [get|getnext|walk] agent community oid [oid ...]\n"); printf( " snmputil trap\n"); return 1; } // Get agent address... argumentVector++; argumentCount--; agent = (LPSTR)SNMP_malloc(strlen(*argumentVector) + 1); strcpy(agent, *argumentVector); // Get agent community... argumentVector++; argumentCount--; community = (LPSTR)SNMP_malloc(strlen(*argumentVector) + 1); strcpy(community, *argumentVector); // Get oid's... variableBindings.list = NULL; variableBindings.len = 0; while(--argumentCount) { AsnObjectIdentifier reqObject; argumentVector++; // Convert the string representation to an internal representation. if (!SnmpMgrStrToOid(*argumentVector, &reqObject)) { printf("Error: Invalid oid, %s, specified.\n", *argumentVector); return 1; } else { // Since sucessfull, add to the variable bindings list. variableBindings.len++; if ((variableBindings.list = (RFC1157VarBind *)SNMP_realloc( variableBindings.list, sizeof(RFC1157VarBind) * variableBindings.len)) == NULL) { printf("Error: Error allocating oid, %s.\n", *argumentVector); return 1; } variableBindings.list[variableBindings.len - 1].name = reqObject; // NOTE! structure copy variableBindings.list[variableBindings.len - 1].value.asnType = ASN_NULL; } } // end while() // Make sure only one variable binding was specified if operation // is WALK. if (operation == WALK && variableBindings.len != 1) { printf("Error: Multiple oids specified for WALK.\n"); return 1; } // Establish a SNMP session to communicate with the remote agent. The // community, communications timeout, and communications retry count // for the session are also required. if ((session = SnmpMgrOpen(agent, community, timeout, retries)) == NULL) { printf("error on SnmpMgrOpen %d\n", GetLastError()); return 1; } } // end if(TRAP) // Determine and perform the requested operation. if (operation == GET || operation == GETNEXT) { // Get and GetNext are relatively simple operations to perform. // Simply initiate the request and process the result and/or // possible error conditions. if (operation == GET) requestType = ASN_RFC1157_GETREQUEST; else requestType = ASN_RFC1157_GETNEXTREQUEST; // Request that the API carry out the desired operation. if (!SnmpMgrRequest(session, requestType, &variableBindings, &errorStatus, &errorIndex)) { // The API is indicating an error. printf("error on SnmpMgrRequest %d\n", GetLastError()); } else { // The API succeeded, errors may be indicated from the remote // agent. switch(errorStatus) { case SNMP_ERRORSTATUS_TOOBIG: { printf("SNMP_ERRORSTATUS_TOOBIG"); break; } case SNMP_ERRORSTATUS_NOSUCHNAME: { printf("SNMP_ERRORSTATUS_NOSUCHNAME"); break; } case SNMP_ERRORSTATUS_BADVALUE: { printf("SNMP_ERRORSTATUS_BADVALUE"); break; } default: break; } if (errorStatus > 0) { printf("Error: errorStatus=%d, errorIndex=%d\n", errorStatus, errorIndex); } else { // Display the resulting variable bindings. UINT i; char *string = NULL; for(i=0; i < variableBindings.len; i++) { SnmpMgrOidToStr(&variableBindings.list[i].name, &string); printf("Variable = %s\n", string); if (string) SNMP_free(string); printf("Value = "); SnmpUtilPrintAsnAny(&variableBindings.list[i].value); printf("\n"); } // end for() } // Free the variable bindings that have been allocated. SnmpUtilVarBindListFree(&variableBindings); } } else if (operation == WALK) { // Walk is a common term used to indicate that all MIB variables // under a given OID are to be traversed and displayed. This is // a more complex operation requiring tests and looping in addition // to the steps for get/getnext above. AsnObjectIdentifier root; AsnObjectIdentifier tempOid; SnmpUtilOidCpy(&root, &variableBindings.list[0].name); requestType = ASN_RFC1157_GETNEXTREQUEST; while(1) { if (!SnmpMgrRequest(session, requestType, &variableBindings, &errorStatus, &errorIndex)) { // The API is indicating an error. printf("error on SnmpMgrRequest %d\n", GetLastError()); break; } else { // The API succeeded, errors may be indicated from the remote // agent. // Test for end of subtree or end of MIB. if (errorStatus == SNMP_ERRORSTATUS_NOSUCHNAME || SnmpUtilOidNCmp(&variableBindings.list[0].name, &root, root.idLength)) { printf("End of MIB subtree.\n\n"); break; } // Test for general error conditions or sucesss. if (errorStatus > 0) { printf("Error: errorStatus=%d, errorIndex=%d \n", errorStatus, errorIndex); break; } else { // Display resulting variable binding for this iteration. char *string = NULL; SnmpMgrOidToStr(&variableBindings.list[0].name, &string); printf("Variable = %s\n", string); if (string) SNMP_free(string); printf("Value = "); SnmpUtilPrintAsnAny(&variableBindings.list[0].value); printf("\n"); } } // end if() // Prepare for the next iteration. Make sure returned oid is // preserved and the returned value is freed. SnmpUtilOidCpy(&tempOid, &variableBindings.list[0].name); SnmpUtilVarBindFree(&variableBindings.list[0]); SnmpUtilOidCpy(&variableBindings.list[0].name, &tempOid); variableBindings.list[0].value.asnType = ASN_NULL; SnmpUtilOidFree(&tempOid); } // end while() // Free the variable bindings that have been allocated. SnmpUtilVarBindListFree(&variableBindings); SnmpUtilOidFree(&root); } else if (operation == TRAP) { // Trap handling can be done two different ways: event driven or // polled. The following code illustrates the steps to use event // driven trap reception in a management application. HANDLE hNewTraps = NULL; if (!SnmpMgrTrapListen(&hNewTraps)) { printf("error on SnmpMgrTrapListen %d\n", GetLastError()); } else { printf("snmputil: listening for traps...\n"); } while(1) { DWORD dwResult; if ((dwResult = WaitForSingleObject(hNewTraps, 0xffffffff)) == 0xffffffff) { printf("error on WaitForSingleObject %d\n", GetLastError()); } else if (!ResetEvent(hNewTraps)) { printf("error on ResetEvent %d\n", GetLastError()); } else { AsnObjectIdentifier enterprise; AsnNetworkAddress IPAddress; AsnInteger genericTrap; AsnInteger specificTrap; AsnTimeticks timeStamp; RFC1157VarBindList variableBindings; UINT i; char *string = NULL; while(SnmpMgrGetTrap(&enterprise, &IPAddress, &genericTrap, &specificTrap, &timeStamp, &variableBindings)) { printf("snmputil: trap generic=%d specific=%d\n", genericTrap, specificTrap); if (IPAddress.length == 4) { printf(" from -> %d.%d.%d.%d\n", (int)IPAddress.stream[0], (int)IPAddress.stream[1], (int)IPAddress.stream[2], (int)IPAddress.stream[3]); } if (IPAddress.dynamic) { SNMP_free(IPAddress.stream); } for(i=0; i < variableBindings.len; i++) { SnmpMgrOidToStr(&variableBindings.list[i].name, &string); printf("Variable = %s\n", string); if (string) SNMP_free(string); printf("Value = "); SnmpUtilPrintAsnAny(&variableBindings.list[i].value); } // end for() printf("\n"); SnmpUtilOidFree(&enterprise); SnmpUtilVarBindListFree(&variableBindings); } } } // end while() } // end if(operation) if (operation != TRAP) { // Close SNMP session with the remote agent. if (!SnmpMgrClose(session)) { printf("error on SnmpMgrClose %d\n", GetLastError()); return 1; } } // Let the command interpreter know things went ok. return 0; } // end main()
以下是MAKEFILE文件
# Nmake macros for building Windows 32-Bit apps TARGETOS=WINNT !include <ntwin32.mak> !if "$(CPU)" == "i386" cflags = $(cflags) -D_CRTAPI1=_cdecl -D_CRTAPI2=_cdecl !else cflags = $(cflags) -D_CRTAPI1= -D_CRTAPI2= !endif all: snmputil.exe snmputil.obj: snmputil.c $(cc) $(cflags) $(cvars) $(cdebug) snmputil.c snmputil.exe: snmputil.obj $(link) $(linkdebug) $(conflags) -out:snmputil.exe snmputil.obj $(conlibsdll) \ advapi32.lib snmpapi.lib mgmtapi.lib
如果开始有链接错误,那么八成是因为需要加入mgmtapi.lib snmpapi.lib 这两个库文件到链接选项里。
运行这个程序生成snmputil.exe
2.3 运行在命令模式下输入 snmputil get 你的IP地址或者用户名 public .1.3.6.1.2.1.1.1.0
是不是看到了你机器地相关信息。如果是网络上地其他机器,如果安装了SNMP,也可以看到他的信息。至于为什么什么用,就请您再接再厉地学习了。
本文地址:http://com.8s8s.com/it/it27611.htm