1. 程式人生 > >net-snmp agent開發詳解,非常簡單

net-snmp agent開發詳解,非常簡單

轉載請標明出處 原文地址:http://blog.csdn.net/hepeng597/article/details/8782868

花了一兩天時間測試和整理一下。

用net-snmp擴充套件MIB庫,實現方法可歸結為四種:

1)一是靜態庫方式,通過修改配置標頭檔案,在相應地方包含新引入的mib模組的.c和.h檔案,然後重新編譯庫檔案和擴充套件程式碼;這種方式不夠靈活,每次修改擴充套件的MIB後,都需要重新編譯snmpd和擴充套件的程式碼,再重新安裝snmpd到系統中。

2)二是編譯動態共享庫,只需把新引入的MIB模組的.c和.h檔案編譯成動態庫,通過設定能夠讓代理程式載入。

對於第二種方式,一需要編譯成.so動態共享庫,二需要原代理程式是否包含dlmod或load命令,三還要看系統是否支援。一般情況下僅支援Unix平臺。

3)三是擴充套件一個子代理,讓SNMPD以主代理的模式執行,對於SNMPD我們只要讓它啟動就可以,不需要任何的更改和配置,把子代理編譯生成的程式執行起來就可以擴充套件自定義的MIB庫。

4)用shell指令碼來擴充套件

本文我們以第三種方法在linux上開發和測試

一、安裝snmpd

既然要測試,而且我們用的也是net-snmp工具,當然要先安裝snmpd,本文采用5.7.2版本的snmpd,需安裝net-snmp-5.7.2-1, net-snmp-devel-5.7.2-1,net-snmp-perlmods-5.7.2-1,安裝可以是編譯net-snmp的原始碼,也可以下載rpm包安裝,這裡略過。

安裝好後測試一下service snmpd status,如果沒有反應,可能是沒有配置檔案,可以手動建立/etc/snmp目錄,在snmp目錄下建立snmpd.conf檔案,填入一些基本的配置資訊(或者通過snmpconf程式一步一步生成,snmpconf程式比較容易懂,適合童鞋們,snmpconf會提示你建立什麼配置檔案,需不需要把snmpd作為主代理等等強大的提示):

master agentx
rocommunity public
rwcommunity public

master 是說該snmpd以主代理方式執行,目前主代理snmpd只支援agentx型別,而我們要開發的程式是一種子代理(subagent),是需要連snmpd的master agent的。rocommunity (只讀物件)和rwcommunity(讀寫物件)的密碼都是public.(這個密碼就是客戶端訪問OID時需要提供的密碼,比如在任一一個裝有snmpd的linux機器上,執行snmpwalk -v2c -c public localhost 1.3.6.1.2.1.1, 這裡的public就是密碼,分別有隻讀OID密碼,和讀寫OID密碼),本文測試就以public作為預設的密碼吧。

現在測試一下snmpd是否正常,啟動service snmpd restart,執行snmpwalk -v2c -c public localhost 1.3.6.1.2.1.1, 如果有SNMPv2-MIB:xxxx之類的輸出就表示我們的主代理已經工作了。

二、自己的MIB庫

首先MIB庫有什麼用?其實作為子代理來說,在server機器上,可以不用MIB庫,MIB庫只為了讓使用者訪問時方便,有了MIB庫,使用者就不用記那麼多和長的OID,比如把MIB放在windows機器上,在windows機器裝一個支援MIB的軟體,用該軟體開啟MIB庫,只要點選相應的物件就可以自動傳送snmp請求到server端,所以server端是可以不要MIB庫的。如果把MIB庫放在linux客戶端機器上,以下面自定義的MIB庫為例,那麼就可以直接執行snmpget -v2c -c public Test-MIB::GetTime.0,當然需要linux客戶端裝有snmp,而且自定義的MIB庫必須能讓snmpd程式找到。 

這裡用就一個OID建一個MIB庫來簡化,命名Test-MIB.my,放在/usr/local/share/snmp/mibs目錄下,因為這個目錄是snmpd的預設目錄,只要把MIB庫放入該目錄就可以自動載入MIB庫,否則需要修改/etc/snmp/snmp.conf檔案,新增mibs +/path/to/Test-MIB.my 並重啟snmpd。

自定義MIB庫,如下:

-- Test-MIB.my
    Test-MIB DEFINITIONS ::= BEGIN
 
        IMPORTS
            OBJECT-GROUP, MODULE-COMPLIANCE, NOTIFICATION-GROUP    
                FROM SNMPv2-CONF    
            enterprises, Integer32, Unsigned32, OBJECT-TYPE, MODULE-IDENTITY, 
            NOTIFICATION-TYPE    
                FROM SNMPv2-SMI    
            DisplayString    
                FROM SNMPv2-TC;
    
-- October 09, 2002 at 14:50 GMT
        -- 1.3.6.1.4.1.16535
        Test MODULE-IDENTITY 
            LAST-UPDATED "200210091450Z"        -- October 09, 2002 at 14:50 GMT
            ORGANIZATION 
                ""  
            CONTACT-INFO 
                ""  
            DESCRIPTION 
                "Video's Server MIB."
            ::= { enterprises 16535 }
    
--  Node definitions
-- This part will include all details about the Test.
        -- 1.3.6.1.4.1.16535.1
        Time OBJECT IDENTIFIER ::= { Test 1 } 

    
        -- 1.3.6.1.4.1.16535.1.1
        GetTime OBJECT-TYPE
            SYNTAX DisplayString (SIZE (0..100))
            MAX-ACCESS read-only
            STATUS current
            DESCRIPTION
                "Example : 2013/4/11"
            ::= { Time 1 }
    END

-- Test-MIB.my

很簡單,該MIB庫只有一個OID,即:1.3.6.1.4.1.16535.1.1,寫完後我們測一個MIB庫有沒有問題,在linux機器上用snmptranslate -Tp -IR Test-MIB::Test顯示結果如下:

+--Test(16535)
   |
   +--Time(1)
      |
      +-- -R-- String    GetTime(1)
               Textual Convention: DisplayString
               Size: 0..100

OK, snmp自動發現了這個MIB庫, 有了自定義的OID,但是還沒有處理程式(子代理)

三、生成原始碼

mib2c可以根據mib庫生成對應的原始碼,有多種模板,這裡我們要生成子代理的程式碼,所以選擇是固定的,執行env MIBS="+/usr/local/share/snmp/mibs/Test-MIB.my" mib2c Test,會引導你逐漸生成Test.h和Test.c, 先選2再選1,過程如下:

[[email protected] mibs]# env MIBS="+/etc/snmp/mibs/Test-MIB.my" mib2c Test
writing to -
mib2c has multiple configuration files depending on the type of
code you need to write.  You must pick one depending on your need.

You requested mib2c to be run on the following part of the MIB tree:
  OID:                              Test
  numeric translation:              .1.3.6.1.4.1.16535
  number of scalars within:         1   
  number of tables within:          0   
  number of notifications within:   0   

First, do you want to generate code that is compatible with the 
ucd-snmp 4.X line of code, or code for the newer Net-SNMP 5.X code
base (which provides a much greater choice of APIs to pick from):

  1) ucd-snmp style code
  2) Net-SNMP style code

Select your choice : 2 

**********************************************************************
         GENERATING CODE FOR SCALAR OBJECTS:
**********************************************************************

  It looks like you have some scalars in the mib you requested, so I
  will now generate code for them if you wish.  You have two choices
  for scalar API styles currently.  Pick between them, or choose not 
  to generate any code for the scalars:

  1) If you're writing code for some generic scalars
     (by hand use: "mib2c -c mib2c.scalar.conf Test")

  2) If you want to magically "tie" integer variables to integer
     scalars
     (by hand use: "mib2c -c mib2c.int_watch.conf Test")

  3) Don't generate any code for the scalars

Select your choice: 1
    using the mib2c.scalar.conf configuration file to generate your code.
writing to Test.h
writing to Test.c



**********************************************************************
* NOTE WELL: The code generated by mib2c is only a template.  *YOU*  *
* must fill in the code before it'll work most of the time.  In many *
* cases, spots that MUST be edited within the files are marked with  *
* /* XXX */ or /* TODO */ comments.                                  *
**********************************************************************
running indent on Test.h
running indent on Test.c
mib2c已經統計出我們的mib庫包含1個scalar變數,0個table變數,0個通知變數,Scalar就是包含我們常用的整型,字串,時間等等資料型別。table就是scalar的一種集合,有一個和多個列組成,類似於資料庫中的表。它必須具有索引項,用來按一定順序檢索表項,當然我們只寫了一個標量的OID,不是表結構也不是通知結構

生成的Test.h如下:

/*
 * Note: this file originally auto-generated by mib2c using
 *        $
 */
#ifndef TEST_H
#define TEST_H

/*
 * function declarations 
 */
void            init_Test(void);
Netsnmp_Node_Handler handle_GetTime;

#endif                          /* TEST_H */

生成的Test.c檔案如下:
/*
 * Note: this file originally auto-generated by mib2c using
 *        $
 */

#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>
#include "Test.h"

/** Initializes the Test module */
void
init_Test(void)
{
    const oid       GetTime_oid[] = { 1, 3, 6, 1, 4, 1, 16535, 1, 1 };

    DEBUGMSGTL(("Test", "Initializing\n"));

    netsnmp_register_scalar(netsnmp_create_handler_registration
                            ("GetTime", handle_GetTime, GetTime_oid,
                             OID_LENGTH(GetTime_oid), HANDLER_CAN_RONLY));
}

int
handle_GetTime(netsnmp_mib_handler *handler,
               netsnmp_handler_registration *reginfo,
               netsnmp_agent_request_info *reqinfo,
               netsnmp_request_info *requests)
{
    /*  
     * We are never called for a GETNEXT if it's registered as a
     * "instance", as it's "magically" handled for us.  
     */

    /*  
     * a instance handler also only hands us one request at a time, so
     * we don't need to loop over a list of requests; we'll only get one. 
     */

    switch (reqinfo->mode) {

    case MODE_GET:
        snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
                                 /*
                                  * XXX: a pointer to the scalar's data 
                                  */ ,
                                 /*
                                  * XXX: the length of the data in bytes 
                                  */ );
        break;


    default:
        /*
         * we should never get here, so this is a really bad error 
         */
        snmp_log(LOG_ERR, "unknown mode (%d) in handle_GetTime\n",
                 reqinfo->mode);
        return SNMP_ERR_GENERR;
    }

    return SNMP_ERR_NOERROR;
}

以上的程式碼都是自動生成的,我們沒有寫一行程式碼,到了這一步,我們需要把Test.c裡面的 XXX改成自己的值,也就兩行,修改後Test.c檔案程式碼如下:

/*
 * Note: this file originally auto-generated by mib2c using
 *        $
 */

#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>
#include "Test.h"
#include <time.h>

/** Initializes the Test module */
void
init_Test(void)
{
    const oid       GetTime_oid[] = { 1, 3, 6, 1, 4, 1, 16535, 1, 1 };

    DEBUGMSGTL(("Test", "Initializing\n"));

    netsnmp_register_scalar(netsnmp_create_handler_registration
                            ("GetTime", handle_GetTime, GetTime_oid,
                             OID_LENGTH(GetTime_oid), HANDLER_CAN_RONLY));
}

int
handle_GetTime(netsnmp_mib_handler *handler,
               netsnmp_handler_registration *reginfo,
               netsnmp_agent_request_info *reqinfo,
               netsnmp_request_info *requests)
{
    /*  
     * We are never called for a GETNEXT if it's registered as a
     * "instance", as it's "magically" handled for us.  
     */
     /*
     * a instance handler also only hands us one request at a time, so
     * we don't need to loop over a list of requests; we'll only get one. 
     */

    time_t t;
    switch (reqinfo->mode) {
    case MODE_GET:
        time(&t);
        char szTime[100];
        snprintf(szTime,100,"%s",ctime(&t));
        snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
                                 /*
                                  * XXX: a pointer to the scalar's data 
                                  */ szTime,
                                 /*
                                  * XXX: the length of the data in bytes 
                                  */ strlen(szTime));
        break;


    default:
        /*
         * we should never get here, so this is a really bad error 
         */
        snmp_log(LOG_ERR, "unknown mode (%d) in handle_GetTime\n",
                 reqinfo->mode);
        return SNMP_ERR_GENERR;
    }

    return SNMP_ERR_NOERROR;
}
簡單吧,現在子代理程式基本就寫完了,我們執行命令讓我們的子代理生成可執行程式,執行

net-snmp-config --compile-subagent Test Test.c,生成了Test程式, 執行過程如下:



可以看出來,net-snmp-config程式生成了一個臨時的C檔案,netsnmptmp.12373.c 並與Test.c一起編譯,生成了Test程式後又刪除了該臨時檔案。我們會在最後研究netsnmptmp.12373.c檔案。

四、測試一下

現在Test程式已經生成了,我們先執行主代理(service snmpd start),再執行子代理./Test,再ps -ef | grep Test,看一下,可以看到Test程式自動在後臺啟動了,如下:

[[email protected] hepeng]# ps -ef| grep Test 
root     27526     1  0 13:29 ?        00:00:00 ./Test
root     27531 27448  0 13:29 pts/2    00:00:00 grep Test
到這裡我們可以想象到,Test.c檔案中是沒有main函式的,那麼main函式肯定是在netsnmptmp.12373.c 中,net-snmp-config讓Test程式變成了守護程序在後臺執行。

到此我們的service端就已經佈置完成了,子代理理論上可以回覆自定義的GetTime OID的請求。

本文在一臺裝有snmpd和子代理的linux server機器上直接測試。執行命令如下:

[[email protected] hepeng]# snmpget -v2c -c public localhost 1.3.6.1.4.1.16535.1.1.0
SNMPv2-SMI::enterprises.16535.1.1.0 = STRING: "Thu Apr 11 13:40:20 2013
"
可以看到,我們開發的子代理成功工作了。如果自定義的MIB庫已經加入到snmpd指定的目錄中,我們可以執行
[[email protected] ~]$ snmpget -v2c -c public localhost Test-MIB:GetTime.0
Test-MIB::GetTime.0 = STRING: Thu Apr 11 13:46:42 2013
snmpget會自動在所有的MIB庫中查詢Test-MIB庫,並把Test-MIB:GetTime.0轉換成1.3.6.1.4.1.16535.1.1.0併發送get請求。

現在子代理是已經開發成功了,我們實際上只寫了兩三行程式碼就開發了net-snmp子代理,是不是很簡單呢?

現在有個問題,怎麼加入到我們自己的專案中呢?因為Test.c中並沒有main函式,在一個專案中直接呼叫init_Test()能不能讓子代理work呢?那就要研究一下netsnmptmp.12373.c。

五、加入專案中

我們再次執行net-snmp-config --compile-subagent Test Test.c,然後立刻Ctrl+c,時間要控制好,讓net-snmp-config程式產生了臨時的C檔案,卻沒有刪除它。開啟netsnmptmp.12373.c,我們來看一下程式碼,200多行,本文只貼上main函式的重要部分,程式碼中都添加了註釋,不難理解:

int main (int argc, char **argv)
{
  int arg;
  char* cp = NULL;
  int dont_fork = 0, do_help = 0;

  while ((arg = getopt(argc, argv, "dD:fhHL:"
#ifndef DISABLE_MIB_LOADING
                       "m:M:"
#endif /* DISABLE_MIB_LOADING */
                       "n:"
#ifndef DISABLE_MIB_LOADING
                       "P:"
#endif /* DISABLE_MIB_LOADING */
                       "vx:")) != EOF) {
    switch (arg) {
    case 'D':/*這裡省略多個case break,只是一些選項,沒必要研究/
      break;

    default:
      fprintf(stderr, "invalid option: -%c\n", arg);
      usage(argv[0]);
      break;
    }
  }

  if (do_help) {
    netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,
                           NETSNMP_DS_AGENT_NO_ROOT_ACCESS, 1);
  } else {
    /* we are a subagent  第一步:這裡是告訴snmpd我們這個Test作為子代理*/
    netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,
                           NETSNMP_DS_AGENT_ROLE, 1);

    if (!dont_fork) {/* 這裡是讓Test程式變成守護程序,執行Test後可以在後臺執行不會退出 */
      if (netsnmp_daemonize(1, snmp_stderrlog_status()) != 0)
        exit(1);
    }

    /* initialize tcpip, if necessary */
    SOCK_STARTUP;
  }

  /* initialize the agent library 第二步*/
  init_agent(app_name);

  /* initialize your mib code here 第三步*/
  init_Test();

  /* Test will be used to read Test.conf files. 第四步 */
  init_snmp("Test");

  if (do_help) {
    fprintf(stderr, "Configuration directives understood:\n");
    read_config_print_usage("  ");
    exit(0);
  }

  /* In case we received a request to stop (kill -TERM or kill -INT) */
  netsnmp_running = 1;
#ifdef SIGTERM
  signal(SIGTERM, stop_server);
#endif
#ifdef SIGINT
  signal(SIGINT, stop_server);
#endif
#ifdef SIGHUP
  signal(SIGHUP, hup_handler);
#endif

  /* main loop here... */
  while(netsnmp_running) {
    if (reconfig) {
      free_config();
      read_configs();
      reconfig = 0;
    }
    agent_check_and_process(1);
  }

  /* at shutdown time */
  snmp_shutdown(app_name);

  /* deinitialize your mib code here */

  /* shutdown the agent library */
  shutdown_agent();
  SOCK_CLEANUP;
  exit(0);
}

我們不管上面程式碼那些看不懂的函式,知道大概意思就行,現在我們來加入到自己的專案中,找到專案中的main函式,在main函式中新增初始化Test子代理的程式碼,本文為了方便理解,就在Test.c中新增main函式,就地取材,寫個超簡單函式,不考慮傳入引數。修改後的Test.c檔案如下:
/*
 * Note: this file originally auto-generated by mib2c using
 *        $
 */

#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>
#include "Test.h"
#include <time.h>

/** Initializes the Test module */
void
init_Test(void)
{
    const oid       GetTime_oid[] = { 1, 3, 6, 1, 4, 1, 16535, 1, 1 };

    DEBUGMSGTL(("Test", "Initializing\n"));

    netsnmp_register_scalar(netsnmp_create_handler_registration
                            ("GetTime", handle_GetTime, GetTime_oid,
                             OID_LENGTH(GetTime_oid), HANDLER_CAN_RONLY));
}

int
handle_GetTime(netsnmp_mib_handler *handler,
               netsnmp_handler_registration *reginfo,
               netsnmp_agent_request_info *reqinfo,
               netsnmp_request_info *requests)
{
    /*
     * We are never called for a GETNEXT if it's registered as a
     * "instance", as it's "magically" handled for us.  
     */
    /*
     * a instance handler also only hands us one request at a time, so
     * we don't need to loop over a list of requests; we'll only get one. 
     */

    time_t t;
    switch (reqinfo->mode) {
    case MODE_GET:
    time(&t);
    char szTime[100];
    snprintf(szTime,100,"%s",ctime(&t));
        snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
                                 /*
                                  * XXX: a pointer to the scalar's data 
                                  */ szTime,
                                 /*
                                  * XXX: the length of the data in bytes 
                                  */ strlen(szTime));
        break;


    default:
        /*
         * we should never get here, so this is a really bad error 
         */
        snmp_log(LOG_ERR, "unknown mode (%d) in handle_GetTime\n",
                 reqinfo->mode);
        return SNMP_ERR_GENERR;
    }

    return SNMP_ERR_NOERROR;
}

static int keep_running;
RETSIGTYPE stop_server(int __attribute__((unused)) a) {
        keep_running = 0;
}

int main()
{
   const char *app_name = "Test";
   /* we are a subagent */
   netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, 1);

   /* initialize the agent library */
   init_agent(app_name);

   /* initialize your mib code here */
   init_Test();

   /* Test will be used to read Test.conf files. */
   init_snmp("Test");
   keep_running = 1;
   while(keep_running)
   {
        agent_check_and_process(1);/* block every 1 second */
   }
   /* at shutdown time */
   snmp_shutdown(app_name);

   /* deinitialize your mib code here */

   /* shutdown the agent library */
   shutdown_agent();
   return 0;
}

這個main函式是不是很簡單呢?當snmpd stop的時候會呼叫stop_server,也就會登出我們的子代理。編譯一下,這裡我們不用net-snmp-config編譯,因為是要加入到自己的專案中,所以推薦寫入到Makefile中,本文就不寫Makefile了,直接呼叫gcc命令生成(直接用net-snmp-config的引數就可以),如下:
[[email protected] hepeng]# gcc  -fno-strict-aliasing -g -O2 -Ulinux -Dlinux=linux  -D_REENTRANT -D_GNU_SOURCE -fno-strict-aliasing -pipe -Wdeclaration-after-statement -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -I/usr/include/gdbm  -I/usr/lib64/perl5/5.8.8/x86_64-linux-thread-multi/CORE   -I. -I/usr/local/include -o Test Test.c  -L/usr/local/lib -lnetsnmpmibs -lnetsnmpagent -lnetsnmp -lnetsnmpmibs -lpci -lrpm -lrpmdb -lrpmio   -lnetsnmpagent  -Wl,-E -Wl,-rpath,/usr/lib64/perl5/5.8.8/x86_64-linux-thread-multi/CORE -lnetsnmp  -lcrypto
Test.c: In function ‘handle_GetTime’:
Test.c:45: warning: ISO C90 forbids mixed declarations and code

然後我們啟動snmpd,再執行Test程式,程式會block住,因為不是守護程序嘛,而且main有迴圈,如下:
[[email protected] ~]# ./Test 
NET-SNMP version 5.7.2 AgentX subagent connected
我們再呼叫snmpget來測試結果:
[[email protected] hepeng]# snmpget -v2c -c public localhost 1.3.6.1.4.1.16535.1.1.0
SNMPv2-SMI::enterprises.16535.1.1.0 = STRING: "Thu Apr 11 02:39:17 2013
"

六、總結

子代理看起來非常好寫,我們實際上就寫了兩三行,其它的函式看不懂也沒關係, 不用深入瞭解,拷貝過來直接用,能編譯過就行,一般看函式名字就知道怎麼用。

子代理官方參考:http://www.net-snmp.org/wiki/index.php/TUT:Writing_a_Subagent

動態庫擴充套件MIB庫方法:http://www.net-snmp.org/wiki/index.php/TUT:Writing_a_Dynamically_Loadable_Object

shell指令碼擴充套件MIB庫方法:http://www.net-snmp.org/wiki/index.php/Tut:Extending_snmpd_using_shell_scripts


相關推薦

net-snmp agent開發非常簡單

轉載請標明出處 原文地址:http://blog.csdn.net/hepeng597/article/details/8782868 花了一兩天時間測試和整理一下。 用net-snmp擴充套件MIB庫,實現方法可歸結為四種: 1)一是靜態庫方式,通過修改配置標頭檔案,

net-snmp agent開發

轉載請標明出處 原文地址:http://blog.csdn.net/hepeng597/article/details/8782868 花了一兩天時間測試和整理一下。 用net-snmp擴充套件MIB庫,實現方法可歸結為四種: 1)一是靜態庫方式,通

基於net-snmp的代理agent開發

花了一兩天時間測試和整理一下。 用net-snmp擴充套件MIB庫,實現方法可歸結為四種: 1)一是靜態庫方式,通過修改配置標頭檔案,在相應地方包含新引入的mib模組的.c和.h檔案,然後重新編譯庫檔案和擴充套件程式碼;這種方式不夠靈活,每次修改擴

【大資料演算法】:apriori演算法非常清晰

 Apriori演算法例項 交易ID 商品ID列表 T100 I1,I2,I5 T200 I2,I4 T300 I2,I3 T400 I1,I2,I4 T500 I1,I3 T600 I2,I3 T700 I1

NPAPI開發Windows版

本文通過多圖組合,詳細引導初學者開發NPAPI的瀏覽器外掛。 1. 準備工作 開發工具 本例使用的是visual studio 2008 英文版,下圖是關於資訊  Windows SDK 本例使用Windows7作業系統 這裡下載SDK NPAPISDK 本例使用的是Firefox4.0.

Android openGl開發(一)——繪製簡單圖形

學習五部曲,弄清楚5個W一個H(when(什麼時候使用)、where(在哪個地方使用?)、who(對誰使用)、what(是個什麼東西)、why(為什麼要這麼用?).一個H即:how(到底該怎麼用?)),基本的概念篇主要圍繞這幾個方面進行分析

【轉】Quartz.net持久化與集群部署開發

疑惑 sum 常用 drive wid res net github hub 轉自:http://www.cnblogs.com/knowledgesea/p/5145239.html 序言 我前邊有幾篇文章有介紹過quartz的基本使用語法與類庫。但是他的執行計劃都是被寫

ZCU106開發之AXI_Bram(重磅推出進階必備)

感謝大家兩週的等待!!本週連發兩篇!!!!  最近團隊事情比較多,在忙ZCU106的視訊處理方面的開發實現了編解碼,RTSP視訊流,影象疊加等應用。如果有朋友想了解更多相關資訊請加QQ群836535064。我們會將相關資料釋出於QQ群中。 歡迎有需求的朋友深度合作。本團隊

ZCU106開發之AXI_HP(重磅推出進階必備)

感謝大家的等待!! 如果有朋友想了解更多相關資訊請加QQ群836535064。我們會將相關資料釋出於QQ群中。 歡迎有需求的朋友深度合作。本團隊專注於高速視訊編解碼,高速訊號採集處理方案提供。同樣也請入群加管理員。 ZCU106開發詳解之AXI_Bram(重磅推

ZCU106開發之PS側SD卡FAT32檔案系統(高階外設大神之路)

感謝大家的等待!! 本週將四連發,我們團隊也將盡自己能力為大家答疑解惑!!! 如果有朋友想了解更多相關資訊請加QQ群836535064。我們會將相關資料釋出於QQ群中。 歡迎有需求的朋友深度合作。本團隊專注於高速視訊編解碼,高速訊號採集處理,高速異構平臺,高速儲存方案提

ZCU106開發之PS側開源TCP/IP協議棧UDP回顯程式(高階外設大神之路)

感謝大家的等待!! 本週將四連發,我們團隊也將盡自己能力為大家答疑解惑!!! 如果有朋友想了解更多相關資訊請加QQ群836535064。我們會將相關資料釋出於QQ群中。 歡迎有需求的朋友深度合作。本團隊專注於高速視訊編解碼,高速訊號採集處理,高速異構平臺,高速儲存方案提

用vue來開發小程式專案極大方便了開發者

案例圖: 五分鐘教程: 通過 Vue.js 命令列工具 vue-cli,你只需在終端視窗輸入幾條簡單命令,即可快速建立和啟動一個帶熱過載、儲存時靜態檢查、內建程式碼構建功能的小程式專案: # 全域性安裝 vue-cli $ npm install

iOS開發-底層篇-Classios底層-class

前言:iOS的開發語言objective-c,它的真實面目是它不是真正的面嚮物件語言,而抽象理解為此而已。其實它就是C+,有個公式可以很好地詮釋那就是 OC = C + Runtime; 接下來我們就好好講講在Runtime下的objc-class。準備資料,objc

大資料開發之倒排索引拭目以待

在現如今,隨著網際網路技術和大資料+人工智慧的飛速發展,越來越多人想要學習大資料開發,那麼今天大資料培訓之倒排索引的詳細介紹,下面我們一起來看一下吧。 首先大資料在經濟、政治、文化等方面有著深遠的影響,大資料可以幫助人們開啟循“數”管理的模式,也是我們當下“大社會”的集中體現,大資料高階班的課程

微信公眾號選單新增小程式miniprogrampagepath引數php開發公眾號

隨著微信小程式功能的開發, 已經可以跟公眾號打通了, 主要有兩種方式: 1) 在公眾號文章中插入小程式 2) 在公眾號選單中新增小程式 第一種方式, 子恆老師在前面的課程已經詳細介紹過, 今天來講第二種方法, 怎麼通過開發的方式實現。 一、 公眾

嵌入式初學者學習嵌入式必看必看書籍列表有電子檔的同學可以共享出來謝謝 Linux基礎 1、《Linux與Unix Shell 程式設計指南》 2、《嵌入式Linux應用程式開發

嵌入式初學者參考書目 無論學習哪方面的程式設計,都需要掌握基礎知識和程式語言,其中《深入理解計算機作業系統》是比較重要的。下面是一些計算機關於嵌入式方面的推薦,有些是借鑑他人的歸納。 Linux基礎 1、《Linux與Unix Shell 程式設計指南》 2、《嵌入式Linux應用程式開發詳

android介面開發:ViewPager的並用於仿微博滑動例項和圖片滾動例項

1.ViewPager簡單使用 ViewPager是android擴充套件包android.support.v4 裡的一個繼承與ViewGroup元件,通過佈局管理器可以實現左右滑動來顯示不同的View。而這個View由PagerAdapter產生,用法類似於

Echarts資料視覺化series-bar柱形圖開發+完美註釋

全棧工程師開發手冊 (作者:欒鵬) Echarts資料視覺化series-bar柱形圖詳解全解: mytextStyle={ color:"#333", //文字顏色 fontSty

android 開發 View _14 MotionEvent和事件處理與實踐自定義滑動條View

MotionEvent MotionEvent物件是與使用者觸控相關的時間序列,該序列從使用者首次觸控式螢幕幕開始,經歷手指在螢幕表面的任何移動,直到手指離開螢幕時結束。手指的初次觸控(ACTION_DOWN操作),滑動(ACTION_MOVE操作)和擡起(ACTION

javaCV開發之4:轉流器實現(也可作為本地收流器、推流器新增新增圖片及文字水印視訊影象幀儲存)實現rtsp/rtmp/本地檔案轉發到rtmp流媒體伺服器(基於javaCV-FFMPEG)

javaCV系列文章: 補充篇: 歡迎大家積極開心的加入討論群 javacpp-ffmpeg: 前言: 本章基於javaCV實現轉流器和收流器功能,測試採用監控rtsp地址轉發至rtmp伺服器地址 新增openCV儲存圖片功能。 補充: