snmp

 
The first two days of the project require an additional function to remotely monitor the running status of the server. It is necessary to regularly monitor the specified port, specified business, and also include the server's disk space, memory, CPU usage, and so on. The first two things are good to say, ping and telnet are also done. If it doesn't work, just open a socket and connect it. The key behind is a bit confusing. If it is local, you can get system information through API, analyze disk space, memory, etc., But getting information from other machines remotely is not a Trojan horse. I checked online and found that SNMP can help with this. So I figured it out and found this to be interesting. Simply take a note.
SNMP Simple Network Management Protocol is a protocol used for network management. It is called simple because it is a simplified version of another network management protocol. That's not to say the simplified version isn't great. On the contrary, the unsimplified network management protocol is so complicated that it is almost impossible to implement and promote it. But to be honest, I don't think SNMP is that simple. After more than ten years of evolution, it is widely used in various network equipment and industrial control. I personally feel that with the further development of the network, electrical appliances will have IP addresses. At times, the role of SNMP or its replacements should be more important.
 
Simply put, SNMP includes three parts: managed devices, agents and network management systems. The managed device refers to the device we want to obtain information, and in this task I need to obtain its disk space. But the managed device just generates this data, the real work of reporting the data back is done by the agent. An agent is simply a program running on a managed device. From the perspective of network programming, it is a small socket service program, which seems to be listening on port 161. On the managed device, the snmp service needs to be started. For example, on Linux, you need to execute service snmpd start to start the snmp service, that is, to run the agent. In the actual process, the proxy is included on various network devices, including switches, routers and even printers, mobile phones, and modems. The network management system is the program that we want to obtain data from the managed equipment and analyze and process it. One can imagine it running locally. As long as I send a qualified request to the running agent, the agent understands the content of the request from the request, collects the required information from the managed device in its own way, and sends it back, such a network administrator The simple process is completed.
This management method is still very flexible. As long as the request packet conforms to the protocol standard, it does not matter which language is used to develop the network management system. From the perspective of the agent, as long as the request can be monitored and processed normally, the agent can be implemented arbitrarily. I don't know if there is a unified international standard. For example, if you ask me to write an agent, you need to check the number of network ports. I have to return the display size. I don't know if the police will arrest me. At least the customer will ask for a return. . It is precisely because of this flexibility that SNMP can also support large-scale centralized management. The same request for querying storage space can be sent to my PC or my Nokia mobile phone, and I may get a memory card. It depends on how the agent realizes the capacity.
 
As for how to express my request, there is a unified standard here, which is MIB, the abbreviation of Management Information Base, just like a registry, but this registry does not actually store values, unlike the Windows registry. It just assigns a number to each kind of device information, called OID. This number is organized in the form of a tree with dots in the middle for easy management. When you agree to check, you can directly report this number to know what the check value is. This number is unified by everyone. For example, everyone has eyes. We can measure the quality of the eyes by visual acuity. We can set it like this: "People (1). 4). Vision (5)". Then if I send a request to a person and ask him about his vision, I can say to him: Who is who, who is who, who is who, who is who, tell me. 1.2.3.4.5.0 Here's "1.2.3.4.5" is the object identifier, followed by .0 is the instance identifier.
 
For the sake of simplicity, snmp specifies fewer types of operations. The basic commonly used ones are Get (Get), Set (Set), Get Next (GetNext), and one (Trap) that is actively issued by the agent to report events. In addition, snmp has developed to V3, and what has been added to GetBulk and so on in this process. I haven't used it yet, so I don't dare to talk nonsense. Go back and try again and take notes.
 
Under linux, to configure the SNMP service, you need to modify /etc/snmp/snmpd.conf. You can also configure it through the snmpconf command, which is very convenient.
Under Windows, directly in the control panel, add or remove programs, add Windows components, then select network management, and install the snmp service. Find it in the service list and configure it through properties.
 
Those are the basic concepts. When actually developing, there are several options:
1. Send UDP packets directly, which is the most primitive, the most flexible, and basically completely autonomous. But too much trouble. There is no need to reinvent the wheel to play.
2. Use the winsnmp API on Windows. It takes care of the work of the package.
3. Select some open source SNMP development packages. For example, like NET-SNMP, SNMP++, and many others. There is also a ready-made component OLEPRNLib under .net, I don't know if it should be that kind.
 
I mainly used winsnmp and SNMP++ this time.
First SnmpStartup about. It will return 5 values ​​through 5 parameters. Basic information about the native SNMPAPI, version number and SNMP version. The first two versions use the community name for authentication. Convenient, but less secure. V3 is more secure.
if (SNMPAPI_SUCCESS == SnmpStartup((smiLPUINT32)&m_nMajorVersion, (smiLPUINT32)&m_nMinorVersion, (smiLPUINT32)&m_nLevel, (smiLPUINT32)&m_nTranslateMode, (smiLPUINT32)&m_nRetransmitMode))
on my machine are: 2,0,2,1 ,1
The first two numbers indicate that my WinSnmp version is 2.0.
The third 2, indicating that WinSnmp supports standard SNMPv2
The fourth 1 indicates that my SNMP adopts the conversion mode of SNMPAPI_UNTRANSLATED_V1.
The last 1 indicates that retransmission is supported.
The task is relatively tight, the specific meaning of these parameters, I will go back to study and make notes.
m_hSession = SnmpCreateSession(NULL, 0, CSNMPManager::snmp_callbacknext, this);
Establish a session. With this session, requests can be sent.
The first parameter is the window handle, which is used to receive messages. So, as far as I understand, SNMP can transmit asynchronously in the first place. That is to say, after the request is sent, it does not block. Then if there is a response message, a message will be given to the window handle. If it is under MFC, message mapping can be done. The second parameter is the corresponding message value that the window will receive when a response is received in the future. Then what is the specific response, go to the parameters of the message to see.
Here I pass empty, because the program I tested has no window.
第三个参数是一个函数指针。不发消息给窗口,就可以申请回调。我现在用的就是回调。第四个参数是调回调的时候,传给我的自定义参数,可以传空。我现在传this是因为我注册的snmp_callbacknext是个静态函数。我把实例指针传进去,是为了把实例信息带进去。
接下来,就可以通过SnmpStrToEntity,得到SNMP实体了。这里把客户端和服务端统称为实体。m_hsrcAgent   =   SnmpStrToEntity(m_hSession,   m_pSrcAddr))得到实体句柄
再接下来,m_hContext = SnmpStrToContext(m_hSession, &community);得到上下文句柄。这里的团体名,有人也叫共同体。总之是个帐户一样的东西。在配置SNMP的时候,要设置这个,并给它设置只读还是读写。一般安全起见,设成只读。已经够用了。
现在可以建立变量绑定表了,HSNMP_VBL hVbl = SnmpCreateVbl(m_hSession, NULL, NULL);后两个参数是OID和值。可以一次性建好变量绑定表。我这里是先建了一个空的,一会儿再往里填值。
这里就用到OID了,但我们习惯的“1.3.6.1...”这种字符串形式,需要通过SnmpStrToOid转成smiOID类型。这是为了API拼SNMP包方便,定义的一个新类型。因为最终的SNMP请求的UDP包,是字节形式的。是要符合BER编码规范的。所谓BER编码,就是将一个数据封装成:标志,长度,内容这样一个数据段。比如规定整形标志是1,再假设1234的十六进制是0x12,0x34。那么我要发一个1234出去就要这样编码:01 02 12 34。
将变量加入到变量绑定表:SnmpSetVb(hVbl, 0, &oid, NULL),第二个参数是索引,第三个参数是变量,第四个参数是值。
hSendPDU = SnmpCreatePdu(m_hSession, SNMP_PDU_GETNEXT, 0, 0, 0, hVbl);构造实际的UDP包。PDU:协议数据单元。第二个参数说明请求的类型:可以传一开始提到的那几种类型,snmp.h里面有定义:
#define SNMP_PDU_GET                (ASN_CONTEXT | ASN_CONSTRUCTOR | 0x0)
#define SNMP_PDU_GETNEXT            (ASN_CONTEXT | ASN_CONSTRUCTOR | 0x1)
#define SNMP_PDU_RESPONSE           (ASN_CONTEXT | ASN_CONSTRUCTOR | 0x2)
#define SNMP_PDU_SET                (ASN_CONTEXT | ASN_CONSTRUCTOR | 0x3)
#define SNMP_PDU_V1TRAP             (ASN_CONTEXT | ASN_CONSTRUCTOR | 0x4)
#define SNMP_PDU_GETBULK            (ASN_CONTEXT | ASN_CONSTRUCTOR | 0x5)
#define SNMP_PDU_INFORM             (ASN_CONTEXT | ASN_CONSTRUCTOR | 0x6)
#define SNMP_PDU_TRAP               (ASN_CONTEXT | ASN_CONSTRUCTOR | 0x7)
 
一切就绪,最后就要发包了:
SnmpSendMsg(m_hSession, m_hsrcAgent, m_hdstAgent, m_hContext, hSendPDU)
这里面几个参数都是前面准备好的,这个方法就没啥可说的了。正确调用后,就可以等着回应了。
 
在回调函数SNMPAPI_STATUS CALLBACK CSNMPManager::snmp_callback(HSNMP_SESSION hSession,
  HWND hWnd,
  UINT wMsg,
  WPARAM wParam,
  LPARAM lParam,
  LPVOID lpClientData
)
里,我们可以得到一个hSession.这个是代理那边扔过来的。和我们的hSession没啥关系。
之后我们通过这个hSession,调用SnmpRecvMsg(hSession, &hsrcAgent, &hdstAgent, &hContext, &hRecvPDU)),得回实体,上下文,以及响应的PDU。
得到响应的PDU,比较激动的时刻就到了,因为我们要开始拆响应包了,如果从里面拆出了我们想查的值,那就说明OK了,于是调用:
 SnmpGetPduData(hRecvPDU, NULL, NULL, (smiLPINT)&nErrStatus, (smiLPINT)&nErrIndex, &hRecvVbl)
晕,得到了变量绑定表,那就是说还有一层,不过保佑啊,可千万别一层层剥下来,最后得到4个字节值,转换编码一瞅,俩字“挠挠”,呵呵。
int nVblCnt = SnmpCountVbl(hRecvVbl);
得一下变量绑定表的长度。
smiOID oid;
 smiVALUE val;
 for (int i=1; i<=nVblCnt; i++)
 {
  
  SnmpGetVb(hRecvVbl, i, &oid, &val); 
  parseVb(val);
  
  
 }
循环,得一下每一个变量。得到OID的值,可以用SnmpOidToStr得回成字符串的形式看一下,是哪个OID的值。
然后值的类型是smiOID,很像COM里的variant_t。一个类型值拖着一个大的联合体。
有:
#define SNMP_SYNTAX_INT         (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x02)
#define SNMP_SYNTAX_BITS        (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x03)
#define SNMP_SYNTAX_OCTETS      (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x04)
#define SNMP_SYNTAX_NULL        (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x05)
#define SNMP_SYNTAX_OID         (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x06)
#define SNMP_SYNTAX_INT32       SNMP_SYNTAX_INT
#define SNMP_SYNTAX_IPADDR      (ASN_APPLICATION | ASN_PRIMITIVE | 0x00)
#define SNMP_SYNTAX_CNTR32      (ASN_APPLICATION | ASN_PRIMITIVE | 0x01)
#define SNMP_SYNTAX_GAUGE32     (ASN_APPLICATION | ASN_PRIMITIVE | 0x02)
#define SNMP_SYNTAX_TIMETICKS   (ASN_APPLICATION | ASN_PRIMITIVE | 0x03)
#define SNMP_SYNTAX_OPAQUE      (ASN_APPLICATION | ASN_PRIMITIVE | 0x04)
#define SNMP_SYNTAX_NSAPADDR    (ASN_APPLICATION | ASN_PRIMITIVE | 0x05)
#define SNMP_SYNTAX_CNTR64      (ASN_APPLICATION | ASN_PRIMITIVE | 0x06)
#define SNMP_SYNTAX_UINT32      (ASN_APPLICATION | ASN_PRIMITIVE | 0x07)
这几种值类型。常用的有SNMP_SYNTAX_UINT32、SNMP_SYNTAX_OCTETS、SNMP_SYNTAX_OID这几种吧,用法都差不多。没啥问题。
 
代码到这里,架子就基本上搭好了,我们可以传一个OID过去,看看返回值了,我只知道想查什么,可我怎么知道它的OID是什么呀?别急,有一个网站很好, [url]www.mibdepot.com[/url]这上面有很全的MIB资料。分平台,设备,很齐全。可以上它上面去查。我查了一下,在linux下,如果想查磁盘空间,应该去查

HOST-RESOURCES-MIB (v2)Tree

子树,下面有
hrStorage GROUP 1.3.6.1.2.1.25.2
iso(1). org(3). dod(6). internet(1). mgmt(2). mib-2(1). host(25). hrStorage(2)
   hrMemorySize SCALAR read-only KBytes 1.3.6.1.2.1.25.2.2.0
   hrStorageTable TABLE not-accessible SEQUENCE OF 1.3.6.1.2.1.25.2.3
      hrStorageEntry ENTRY not-accessible HrStorageEntry 1.3.6.1.2.1.25.2.3.1
         hrStorageIndex TABULAR read-only Integer32 ( 1..2147483647 ) 1.3.6.1.2.1.25.2.3.1.1
         hrStorageType TABULAR read-only AutonomousType 1.3.6.1.2.1.25.2.3.1.2
         hrStorageDescr TABULAR read-only DisplayString 1.3.6.1.2.1.25.2.3.1.3
         hrStorageAllocationUnits TABULAR read-only Integer32 ( 1..2147483647 ) 1.3.6.1.2.1.25.2.3.1.4
         hrStorageSize TABULAR read-write Integer32 ( 0..2147483647 ) 1.3.6.1.2.1.25.2.3.1.5
         hrStorageUsed TABULAR read-only Integer32 ( 0..2147483647 ) 1.3.6.1.2.1.25.2.3.1.6
         hrStorageAllocationFailures TABULAR read-only Counter32 1.3.6.1.2.1.25.2.3.1.7
hrDeviceTypes OBJ ID     1.3.6.1.2.1.25.3.1
这里面有一个表,表下面有行,一个分区是一行,每行有索引,有分区描述(一般是卷标),有分区尺寸,有已用空间。
至此,眼前的任务,算是应付下来了。这个过程中,还会牵扯到传输设置,表的操作,GetNext操作的实现等内容,今天实在来不及全记下来了,我稍后再补充完整。

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326350178&siteId=291194637