记一次大华门禁JAVA-linux-SDK的接入经历

接入背景

2020年杭州对交通安全教育及其重视,于是各个街道社区都兴建起了交通治理工作站(交治站),一方面是针对交通违规驾驶员的教育工作,另一方面也是新增一个安全教育的宣传渠道.
我们公司是做VR驾驶的,也有一些设备部署在交治站,因为我们的设备相对是独立的,所以特别开了个小门,并且安装了大华的门禁.想通过二维码扫码,然后服务端远程开门的方式做到24小时开放体验.跟大华的技术咨询后决定以主动注册的方式实现我们的需求.
下面我就说下我的对接历程.

对接历程

注意:接入之前一定要确认自己的设备是否支持二维码事件,如果不支持,是不能使用二维码透传的

1. 接入环境

linux,java,springboot

2.sdk环境搭建

a.首先是需要去官网下载sdk:

https://www.dahuatech.com/service/downloadlists/836.html
我用的是这个sdk,不同环境的不能混用,虽然sdk大部分代码差不多,但也是存在一定差异的

b.包的配置

在这里插入图片描述
当前版本的linux64文件夹


以前版本的linux64

libs文件夹里的jar包按照自己项目的导包方式引入,我的是springboot maven的项目,所以直接上传到了私库里.libs下面的linux64里的一堆依赖文件在linux下是不能直接加载到的,默认是需要放在程序的同级目录的,我试过,并不能加载到,可能是我放的位置有问题.在以前版本的sdk-linux64文件夹下还是有一个说明文件的,我把说明内容贴在下面.

【说明】
Demo以Qt开发,在CentOS上进行编译,以下以CentOS系统为例,说明的Demo使用方式,其他Linux版本参考CentOS系统。
如果SDK各动态库文件和可执行文件在同一级目录下,则使用同级目录下的库文件;此时也可能报找不到库文件的错误,需要显示设置一下环境变量:export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./
如果不在同一级目录下,则需要将以上文件的目录加载到动态库搜索路径中,设置的方式有以下几种:
一. 将网络SDK各动态库路径加入到LD_LIBRARY_PATH环境变量
1.在终端输入:export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/XXX只在当前终端起作用
2. 修改~/.bashrc~/.bash_profile,最后一行添加 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/XXX,保存之后,使用source .bashrc执行该文件 ,当前用户生效
3. 修改/etc/profile,添加内容如第2条,同样保存之后使用source执行该文件 所有用户生效
二.在/etc/ld.so.conf文件结尾添加网络sdk库的路径,如/XXX,保存之后,然后执行ldconfig
三.可以将网络sdk各依赖库放入到/lib64、/lib或usr/lib64、usr/lib下
四.可以在Makefile中使用-Wl,-rpath来指定动态路径,直接将dhnetsdk库以–l方式显示加载进来
比如:-Wl,-rpath=/XXX -lhdhnetsdk
推荐使用一或二的方式,但要注意优先使用的是同级目录下的库文件。

整完以后记得给这些文件读的权限.

3.业务流程

在这里插入图片描述在sdk下的doc里有主动注册的接入文档,另外我还有门禁的配置说明书.

a.设备配置

首先肯定得有门禁设备,按照说明书来配置门禁
门禁说明书

a1.WiFi配置,选择“通讯设置 > 网络设置 > Wi-Fi”,具有 Wi-Fi 模块的设备具有此功能,具体以实物为主。

在这里插入图片描述

a2.配置 IP,选择“通讯设置 > 网络设置 > IP 设置”。我这里直接选择启用DHCP自动获取IP地址

在这里插入图片描述

a3.主动注册,主动注册功能可以使设备对接管理平台,通过管理平台管理设备,选择“通讯设置 > 网络设置 > 主动注册”。

在这里插入图片描述只需配置ip端口即可,记得点击启用.

b.代码实现

目前主要有两种二维码开门的方式:
1、二维码包含卡号信息,刷二维码相当于刷卡开门;
2、刷二维码时,设备上报二维码信息给上层,有上层自己校验二维码信息,再决定是否开门。

接口流程
1、二维码包含卡号信息

1)客户发加密方式和秘钥给设备;
CLIENT_OperateAccessControlManager(NET_EM_ACCESS_CTL_SET_QRCODEDECODE_INFO)
2)客户发卡给设备;
CLIENT_ControlDevice(DH_CTRL_RECORDSET_INSERTEX)
3)客户根据秘钥和卡号生成二维码字符串;
CLIENT_EncryptString
4)客户通过公有的二维码生成方法把二维码字符串转化为二维码;
5)在设备上刷这个二维码的时候,就相当于刷卡,与刷卡开门方式等同。

二维码的秘钥是上层平台传给设备的。生成二维码字符串的时候,就用相同的秘钥去生成。
前三步参考接口如下:

接口:CLIENT_OperateAccessControlManager
对应枚举:

         public static final int NET_EM_ACCESS_CTL_SET_QRCODEDECODE_INFO = 12;      
          // 设置二维码的解码信息, 对应结构体 
          pstInparam = NET_IN_SET_QRCODE_DECODE_INFO,
          pstOutParam = NET_OUT_SET_QRCODE_DECODE_INFO
     // 设置二维码的解码信息入参
     public static class NET_IN_SET_QRCODE_DECODE_INFO extends Structure{
               public int                              dwSize;
               public int                              emCipher; // 加密方式, 参考枚举 NET_ENUM_QRCODE_CIPHER
               public byte[]                       szKey = new byte[33];                    // 秘钥
               public byte[]                       byReserved = new byte[3];                // 字节对齐
               
               public NET_IN_SET_QRCODE_DECODE_INFO() {
                        this.dwSize = this.size();
               }
     }

二维码字符串生成接口:CLIENT_EncryptString
传入卡号、设备的秘钥,生成字符串,这个字符串可以通过公有的二维码生成算法生成二维码。

卡号是平台端向设备发卡,接口CLIENT_ControlDevice
对应控制枚举:
DH_CTRL_RECORDSET_INSERTEX, // 添加指纹记录,获得记录集编号(对应 NET_CTRL_RECORDSET_INSERT_PARAM)

2、二维码上报事件方式

报警订阅接口流程:

CLIENT_Init/CLIENT_Cleanup ---- 初始化/清理库 应用程序开启及关闭时调用一次即可。 
CLIENT_LoginEx2/CLIENT_Logout ----- 登陆/登出设备,CLIENT_Login可以返回一个登陆会话句柄 
CLIENT_SetDVRMessCallBack-----设置报警消息回调函数
CLIENT_StartListenEx/CLIENT_StopListen  开始/停止订阅报警 
CLIENT_SetDVRMessCallBack参数里有个回调函数,有报警触发的时候会收到回调消息

在回调函数中检测对应的事件
#define DH_ALARM_QR_CODE_CHECK 0x335a // 二维码上报事件(对应结构体 ALARM_QR_CODE_CHECK_INFO)

二维码上报事件信息( DH_ALARM_QR_CODE_CHECK )

typedef struct tagALARM_QR_CODE_CHECK_INFO{
	int						nEventID;						// 事件ID
	NET_TIME_EX		        UTC;							// 事件发生的时间
	double					dbPTS;							// 时间戳(单位是毫秒)
	char                    szQRCode[256];                  // 二维码字符串
	BYTE					byReserved[1024];	            // 预留字节
} ALARM_QR_CODE_CHECK_INFO;

客户从ALARM_QR_CODE_CHECK_INFO .szQRCode中获取到二维码信息后,自己去判断是否需要开门,如果需要开门,可以使用以下方式来开门:

接口:CLIENT_ControlDevice
枚举:

DH_CTRL_ACCESS_OPEN,  // 门禁控制-开门(对应结构体 NET_CTRL_ACCESS_OPEN)

我选择的是第二种方式,设备连接到服务端-用户扫码-扫码上传到服务端-服务端处理业务-下发开门控制

基本流程可参考主动注册使用说明书,我这里只把几个流程的代码贴一下
在这里插入图片描述

流程说明
步骤1 调用 CLIENT_Init 初始化接口,完成 SDK 初始化。
步骤2 调用 CLIENT_ListenServer 接口开始监听。CLIENT_ListenServer 接口需要传入主动注
册监听回调函数 fServiceCallBack,通过该回调函数可以获取到注册到本服务平台的设
备的 IP、ID 和端口等信息。监听状态下,回调函数返回设备主动注册传上来的 ID、IP
及端口等信息,用户在回调中获取到信息后可以登录需要的设备并执行其他业务操作。
步骤3 调用 CLIENT_StopListenServer 接口结束监听。
步骤4 调用 CLIENT_Cleanup 接口清理释放 SDK 资源。
注意事项
CLIENT_Init 和 CLIENT_Cleanup 接口需成对调用,支持单线程多次成对调用,但我们建议
全局均只调用一次,勿反复初始化/清理资源。
请确保设备主动注册配置中的目标 IP 与端口和服务器 IP 与端口完全匹配。
服务器只有处于监听状态下时才能向主动注册的设备发起通信,因此所有需要服务器向设备
下发命令的操作都必须在侦听状态下完成,不能中途停止监听。
如果需要在回调函数中调用 SDK 的接口,请另起一个线程执行,否则容易引起程序崩溃。

步骤1
public class InitModule {

    public static NetSDKLib netsdk = NetSDKLib.NETSDK_INSTANCE;

    private static boolean init = false;
    private static boolean bLogopen = false;


    public static boolean init(NetSDKLib.fDisConnect disConnect) {
        init = netsdk.CLIENT_Init(disConnect, null);
        if (!init) {
            //初始化失败
            System.out.println("初始化失败");
            return false;
        }

        //打开日志,可选
        NetSDKLib.LOG_SET_PRINT_INFO setLog = new NetSDKLib.LOG_SET_PRINT_INFO();
        File path = new File("./sdklog/");
        if (!path.exists()) {
            path.mkdir();
        }
        String logPath = path.getAbsoluteFile().getParent() + "\\sdklog\\" + ToolKits.getDate() + ".log";
        setLog.nPrintStrategy = 0;
        setLog.bSetFilePath = 1;
        System.arraycopy(logPath.getBytes(), 0, setLog.szLogFilePath, 0, logPath.getBytes().length);
        System.out.println(logPath);
        setLog.bSetPrintStrategy = 1;
        bLogopen = netsdk.CLIENT_LogOpen(setLog);
        if(!bLogopen ) {
            System.err.println("Failed to open NetSDK log");
        }

        netsdk.CLIENT_SetAutoReconnect(HaveReConnectCallBack.getInstance(), null);
        // 设置更多网络参数,NET_PARAM的nWaittime,nConnectTryNum成员与CLIENT_SetConnectTime
        // 接口设置的登录设备超时时间和尝试次数意义相同,可选
        NetSDKLib.NET_PARAM netParam = new NetSDKLib.NET_PARAM();
        netParam.nConnectTime = 10000;      // 登录时尝试建立链接的超时时间
        netParam.nGetConnInfoTime = 3000;   // 设置子连接的超时时间
        netsdk.CLIENT_SetNetworkParam(netParam);

        System.out.println("初始化成功");
        return true;


    }


    public static void cleanup() {
        if (bLogopen) {
            netsdk.CLIENT_LogClose();
        }
        if (init) {
            netsdk.CLIENT_Cleanup();
        }
    }
}

打开日志这一步其实还是很必要的,纠结了我两天的问题就是通过这个日志解决的.
整个程序结束的时候一定要调用CLIENT_Cleanup 来释放资源.

步骤2

开启监听

public class ApiModule {
	public static NetSDKLib netsdk = NetSDKLib.NETSDK_INSTANCE;

    // 设备信息
    public static NetSDKLib.NET_DEVICEINFO_Ex m_stDeviceInfo = new NetSDKLib.NET_DEVICEINFO_Ex();

    // 登陆句柄
    public static LLong m_hLoginHandle = new LLong(0);
    private static LLong mServerHandler = new LLong(0);

	//开启监听
	public static LLong startServer(String ip) {
        mServerHandler = netsdk.CLIENT_ListenServer(ip, 9500, 1000, ServiceCallBack.getInstance(), null);
        if (0 == mServerHandler.longValue()) {
            System.err.println("Failed to start server." + ToolKits.getErrorCodePrint());
        } else {
            System.out.printf("Start server, [Server address %s][Server port %d]\n", ip, 9500);
        }
        return mServerHandler;
    }
	
}

1.我这里只是个demo,设置的固定端口;
2.需要说明的是,这里开启监听的ip一定要内网ip,不能是公网ip,也不能是127.0.0.1或localhost,在这里也浪费了我好多时间,我以为是我端口的问题,也推荐使用tcpdump工具抓包,用来排查下协议是否接受成功,具体的使用方法可自行百度;
3.CLIENT_ListenServer设置的回调函数,有设备上线时,会回调到那个函数里

监听回调

public class ServiceCallBack implements NetSDKLib.fServiceCallBack {


    private static DelayQueueMsg delayQueueMsg = SpringContext.getBean(DelayQueueMsg.class);

    private ServiceCallBack() {
        System.out.println("监听回调函数初始化");
    }

    private static class CallBackHolder {
        private static ServiceCallBack instance = new ServiceCallBack();
    }

    public static ServiceCallBack getInstance() {
        return ServiceCallBack.CallBackHolder.instance;
    }


    @Override
    public int invoke(NetSDKLib.LLong lHandle, String pIp, int wPort, int lCommand, Pointer pParam, int dwParamLen, Pointer dwUserData) {
        System.out.println("进来啦");
        System.out.println("服务监听回调:login=" + lHandle + ",ip=" + pIp + ",port=" + wPort);
        // 将 pParam 转化为序列号
        byte[] buffer = new byte[dwParamLen];
        pParam.read(0, buffer, 0, dwParamLen);
        String deviceId = "";
        try {
            deviceId = new String(buffer, "GBK").trim();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        System.out.printf("Register Device Info [Device address %s][port %s][DeviceID %s] \n", pIp, wPort, deviceId);
        if (ApiModule.m_hLoginHandle.longValue() == 0) {
            System.out.println("当前线程id:" + Thread.currentThread().getId());
            //登录
            JSONObject object = new JSONObject();
            object.put("pIp", pIp);
            object.put("wPort", wPort);
            object.put("deviceId", deviceId);
            delayQueueMsg.put(new SocketMsgDelay(lHandle.intValue(), object.toJSONString()));
        }
        return 0;
    }
}

1.设备上线,服务端接受回调,需要在这个回调里登录设备
2.我这里使用的是DelayQueue延时队列,异步去处理登录,之所以使用异步,是因为我直接登录的时候会报网络异常,连接失败.大华的技术人员告诉我说是不能在一个线程里调用多个sdk,其实在文档里也是这样建议的,虽然我做的异步,但是还是会报错,具体怎么解决的,我放在下一说明里
不建议使用这个延时队列来做异步,有时候会失效,并不能消费队列,目前我还没有找到问题所在,建议还是使用消息中间件来做队列吧,

登录处理

public static boolean login(String m_strIp, int m_nPort, String m_strUser, String m_strPassword, String deviceIds) {
        Pointer deviceId = ToolKits.GetGBKStringToPointer(deviceIds);
        //入参
        NetSDKLib.NET_IN_LOGIN_WITH_HIGHLEVEL_SECURITY pstInParam = new NetSDKLib.NET_IN_LOGIN_WITH_HIGHLEVEL_SECURITY();
        pstInParam.nPort = m_nPort;
        pstInParam.szIP = m_strIp.getBytes();
        pstInParam.szPassword = m_strPassword.getBytes();
        pstInParam.szUserName = m_strUser.getBytes();
        pstInParam.emSpecCap = 2;//这一步
        pstInParam.pCapParam = deviceId;这一步至关重要
        //出参
        NET_OUT_LOGIN_WITH_HIGHLEVEL_SECURITY pstOutParam = new NET_OUT_LOGIN_WITH_HIGHLEVEL_SECURITY();
        pstOutParam.stuDeviceInfo = m_stDeviceInfo;
        m_hLoginHandle = netsdk.CLIENT_LoginWithHighLevelSecurity(pstInParam, pstOutParam);
        if (m_hLoginHandle.longValue() == 0) {
            System.err.printf("登录设备[%s] 端口[%d]失败. %s\n", m_strIp, m_nPort, ToolKits.getErrorCodePrint());
        } else {
            System.out.println("登录成功 [ " + m_strIp + " ]");
        }
        return m_hLoginHandle.longValue() == 0 ? false : true;
    }public static boolean login(String m_strIp, int m_nPort, String m_strUser, String m_strPassword, String deviceIds) {
        Pointer deviceId = ToolKits.GetGBKStringToPointer(deviceIds);
//        IntByReference nError = new IntByReference(0);
        //入参
        NetSDKLib.NET_IN_LOGIN_WITH_HIGHLEVEL_SECURITY pstInParam = new NetSDKLib.NET_IN_LOGIN_WITH_HIGHLEVEL_SECURITY();
        pstInParam.nPort = m_nPort;
        pstInParam.szIP = m_strIp.getBytes();
        pstInParam.szPassword = m_strPassword.getBytes();
        pstInParam.szUserName = m_strUser.getBytes();
        pstInParam.emSpecCap = 2;
        pstInParam.pCapParam = deviceId;
        //出参
        NET_OUT_LOGIN_WITH_HIGHLEVEL_SECURITY pstOutParam = new NET_OUT_LOGIN_WITH_HIGHLEVEL_SECURITY();
        pstOutParam.stuDeviceInfo = m_stDeviceInfo;
//        m_hLoginHandle = netsdk.CLIENT_LoginEx2(m_strIp, m_nPort, m_strUser, m_strPassword, 2, null, m_stDeviceInfo, nError);
        m_hLoginHandle = netsdk.CLIENT_LoginWithHighLevelSecurity(pstInParam, pstOutParam);
        if (m_hLoginHandle.longValue() == 0) {
            System.err.printf("登录设备[%s] 端口[%d]失败. %s\n", m_strIp, m_nPort, ToolKits.getErrorCodePrint());
        } else {
            System.out.println("登录成功 [ " + m_strIp + " ]");
        }
        return m_hLoginHandle.longValue() == 0 ? false : true;
    }
pstInParam.emSpecCap = 2;
pstInParam.pCapParam = deviceId;

这俩参数至关重要,我也在这里卡了很久,尤其是deviceId,我也是设置了这个才解决了上面那个登录网络异常的问题的

步骤3

这里插播一条,流程图里没有写的,就是监听二维码扫码事件,根据自己的需求处理二维码

/**
     * 订阅报警信息
     *
     * @return
     */
    public static void startListen() {
        // 设置报警回调函数
        netsdk.CLIENT_SetDVRMessCallBack(fAlarmAccessDataCB.getInstance(),
                null);

        // 订阅报警
        boolean bRet = netsdk.CLIENT_StartListenEx(m_hLoginHandle);
        if (!bRet) {
            System.err.println("订阅报警失败! LastError = 0x%x\n"
                    + netsdk.CLIENT_GetLastError());
        } else {
            System.out.println("订阅报警成功.");
        }
    }

/*
     * 报警事件回调 -----门禁事件(对应结构体 ALARM_ACCESS_CTL_EVENT_INFO)
     */
    private static class fAlarmAccessDataCB implements NetSDKLib.fMessCallBack {
        private fAlarmAccessDataCB() {
        }

        private static class fAlarmDataCBHolder {
            private static fAlarmAccessDataCB instance = new fAlarmAccessDataCB();
        }

        public static fAlarmAccessDataCB getInstance() {
            return fAlarmAccessDataCB.fAlarmDataCBHolder.instance;
        }

        public boolean invoke(int lCommand, LLong lLoginID, Pointer pStuEvent,
                              int dwBufLen, String strDeviceIP, NativeLong nDevicePort,
                              Pointer dwUser) {
            System.out.print("command = " + lCommand);
            switch (lCommand) {
                case NetSDKLib.DH_ALARM_QR_CODE_CHECK: // 设备请求对方发起对讲事件
                {
                    NetSDKLib.ALARM_ACCESS_CTL_EVENT_INFO msg = new NetSDKLib.ALARM_ACCESS_CTL_EVENT_INFO();
                    ToolKits.GetPointerData(pStuEvent, msg);
                    System.out.println(msg);
                    //开门或其他业务
                    openDoor();
                    break;
                }

            }

            return true;
        }
    }


public static void openDoor() {

        int emType = NetSDKLib.CtrlType.CTRLTYPE_CTRL_ACCESS_OPEN;

        NetSDKLib.NET_CTRL_ACCESS_OPEN accessOpen = new NetSDKLib.NET_CTRL_ACCESS_OPEN();
        accessOpen.emOpenDoorType = NetSDKLib.EM_OPEN_DOOR_TYPE.EM_OPEN_DOOR_TYPE_REMOTE;
        boolean bRet = netsdk.CLIENT_ControlDevice(m_hLoginHandle, emType,
                accessOpen.getPointer(), 3000);
    }

最后,程序结束时,结束监听,释放资源,大功告成
我这里都只是个demo,所以我只管开,不管关闭与释放资源,大家做的时候,切记都要做的

<think>好的,我现在需要帮助用户将大华SDK集成到本地Java项目中。根据用户提供的引用内容,我需要整理出配置步骤、依赖项添加方法以及可能的问题和解决方案。 首先,用户提到了引用[1]中的安装JDK和IDE,以及下载SDK。所以第一步应该是确认环境是否准备好,包括JDK、IDE和大华SDK的下载。然后,用户需要导入库文件,这里可能需要将下载的SDK中的JAR文件放到项目目录下,比如libs文件夹,这点在引用[2]中的依赖配置里有提到。 接下来是添加依赖项。引用[2]给出了两个依赖项,一个是JNA的公共库,另一个是大华本地的jna.jar。用户需要在pom.xml中添加这两个依赖。这里需要注意版本是否正确,以及systemPath的路径是否正确指向项目中的jar文件。如果用户使用的是Maven项目,这部分配置是必须的,但如果是Gradle项目,可能需要不同的配置方式,不过用户问题中提到的是Java项目,可能默认使用Maven,所以继续按照示例处理。 然后是初始化配置,引用[3]提到用户可能遇到公网访问的问题,转而使用Java后端转发视频流。这可能意味着在代码中需要正确初始化SDK,比如调用DHClient.init()方法,并且处理网络配置,如引用[1]中的网络参数设置,如IP、端口、用户名和密码。 可能的问题方面,引用[3]指出SDK版本或接口不兼容的问题,所以需要确认下载的SDK是否适用于Java项目,并且是否支持所需功能。另外,依赖冲突也是一个常见问题,尤其是JNA的不同版本之间可能存在冲突,需要排除其他版本的JNA。路径问题方面,引用[2]中的systemPath是否正确,需要检查路径是否存在,以及权限是否足够。网络连接问题方面,需要确保设备可达,防火墙设置正确,引用[3]中的公网访问问题可能需要通过后端转发解决,用户可能需要配置NAT或端口映射。 最后,用户可能需要参考大华的官方文档,或者社区资源,比如引用[4]提到的vue项目中的配置,虽然这里是Java项目,但可能有一些配置思路可以借鉴,比如初始化步骤中的参数设置。 总结步骤:准备环境、导入SDK、添加依赖、初始化配置、处理常见问题。需要确保每个步骤都清晰,并且针对可能出现的问题给出解决方案。同时,引用对应的引用标,如[^1]、[^2]等,确保用户知道每个建议的来源。</think>### 大华SDK集成到Java项目的步骤 #### 一、环境准备 1. **安装JDK和IDE** 确保已安装JDK 8+(推荐JDK 11)和IDE(如IntelliJ IDEA或Eclipse)。 2. **下载大华SDK** 从大华官网下载适用于JavaSDK包(如`WEB无插件开发包`),并解压到本地目录[^3]。 --- #### 二、导入库文件 1. **创建`libs`目录** 在项目根目录下新建`libs`文件夹,将SDK中的核心JAR文件(如`dahua-sdk.jar`或`jna.jar`)复制到此处。 2. **配置本地依赖** 在`pom.xml`中添加以下依赖(示例基于Maven): ```xml <!-- JNA公共库 --> <dependency> <groupId>net.java.dev.jna</groupId> <artifactId>jna</artifactId> <version>5.4.0</version> </dependency> <!-- 大华SDK本地JAR --> <dependency> <groupId>com.dahua</groupId> <artifactId>dahua-sdk</artifactId> <version>1.0</version> <scope>system</scope> <systemPath>${project.basedir}/libs/jna.jar</systemPath> </dependency> ``` **注意**:`systemPath`需与实际JAR路径一致。 --- #### 三、初始化配置 1. **加载SDK动态库** 在代码中调用SDK初始化方法(通常需指定动态库路径): ```java public class DahuaSDKInitializer { static { // 加载Windows动态库(示例路径) System.load("C:\\dahua_sdk\\bin\\dhnetsdk.dll"); } public static void init() { DHClient client = new DHClient(); client.init(); // 初始化SDK } } ``` 2. **配置网络参数** 设置设备连接的IP、端口、用户名和密码: ```java DeviceInfo device = new DeviceInfo(); device.setIp("192.168.1.64"); device.setPort(37777); device.setUsername("admin"); device.setPassword("123456"); ``` --- #### 四、常见问题与解决 1. **SDK初始化失败** - **可能原因**:动态库路径错误或权限不足。 - **解决**:检查路径是否正确,并确保程序有权限访问该路径。 2. **依赖冲突** - **现象**:`ClassNotFoundException`或`NoSuchMethodError`。 - **解决**:排除冲突的JNA版本,例如: ```xml <dependency> <groupId>net.java.dev.jna</groupId> <artifactId>jna</artifactId> <version>5.4.0</version> <exclusions> <exclusion> <groupId>com.sun.jna</groupId> <artifactId>jna</artifactId> </exclusion> </exclusions> </dependency> ``` 3. **公网访问问题** - **现象**:SDK无法直连公网设备。 - **解决**:使用后端转发视频流(如通过FFmpeg转码)或配置NAT穿透。 ---
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

奥特大壮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值