摄像机、NVR公网IP不固定解决方案(Java+tcpdump)

it2024-02-02  113

背景:

需要实现海康摄像机外网访问,由于摄像机没有公网IP(这个可以通过端口映射解决),且所在网络不是专线,公网IP会变动。通过DDNS动态域名解析或者使用萤石云、easynvr等云平台也可以解决,但是这些平台都需要付费,且费用较高,于是我就想通过解析协议包的方式来获取摄像机IP并进行更新。

实现步骤:

**一、配置FTP协议。**进入摄像机后台系统,浏览器输入摄像机IP即可,用户名密码默认是admin和a12345678,登录成功后点击“配置”–“网络”–“高级配置”–“FTP”,进行ftp配置,这是摄像机抓拍人脸后向服务器发送图片的协议,若服务器没有搭建FTP服务,可自行百度搭建。 二、捕获协议包。 在ftp服务所在的服务器上通过tcpdump执行sudo tcpdump -i 网卡号 host 网卡号对应的ip地址 and port ftp服务端口号 -w 协议包保存文件.pcap命令抓取ftp服务端口上的协议包并保存,若没有安装tcpdump可百度安装。 三、创建device(摄像机)数据库。

CREATE TABLE `t_device` ( `id` int(10) NOT NULL AUTO_INCREMENT, `devicecode` varchar(200) DEFAULT NULL COMMENT '设备编码', `devicename` varchar(50) DEFAULT NULL COMMENT '设备监控名称', `deviceip` varchar(50) DEFAULT NULL COMMENT '设备ip', `deviceport` varchar(50) DEFAULT NULL COMMENT '设备端口号', `username` varchar(50) DEFAULT NULL COMMENT '设备用户名', `password` varchar(50) DEFAULT NULL COMMENT '设备登录密码', `devicetype` int(10) DEFAULT '1' COMMENT '设备类型(1:摄像机,2:NVR)', `channel` varchar(50) DEFAULT NULL COMMENT 'NVR存通道数,其余存通道id', `vendor` varchar(50) DEFAULT NULL COMMENT '生产厂商(海康:HK,大华:DS)', `position` varchar(50) DEFAULT NULL COMMENT '安装位置', `disknumber` varchar(50) DEFAULT NULL COMMENT '硬盘序列号', `diskchannel` varchar(200) DEFAULT NULL COMMENT '监控点编码', `type` varchar(10) DEFAULT '2' COMMENT '设备状态;1、在线,2、离线', `machinename` varchar(50) DEFAULT NULL COMMENT '门口机名称', `code` varchar(50) DEFAULT NULL COMMENT '单元编号', `uuid` varchar(50) DEFAULT NULL COMMENT '唯一编码', `creattime` timestamp NULL DEFAULT NULL COMMENT '创建时间', `isdelete` int(10) DEFAULT '0' COMMENT '0、未删除,1、已删除', `lon` varchar(50) DEFAULT NULL COMMENT '经度', `lat` varchar(50) DEFAULT NULL COMMENT '纬度', `boxcode` varchar(100) DEFAULT NULL COMMENT '盒子编码', `platformtype` int(1) DEFAULT NULL COMMENT '平台类型:1、感知,2、海康', `publicip` varchar(50) DEFAULT NULL COMMENT '公网ip', `publicport` varchar(50) DEFAULT NULL COMMENT '公网ip端口号', PRIMARY KEY (`id`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=61 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='摄像机管理表';

四、创建maven工程。 1.引入主要依赖并编写application.yml配置文件和application启动类。

<dependency> <groupId>io.pkts</groupId> <artifactId>pkts-streams</artifactId> <version>3.0.3</version> </dependency> <dependency> <groupId>io.pkts</groupId> <artifactId>pkts-core</artifactId> <version>3.0.3</version> </dependency>

2.编写主要代码,其中device为你数据库中摄像头所对应的pojo

import com.pojo.Device; import com.service.DeviceService; import com.zxm.utils.LogUtils; import io.pkts.Pcap; import io.pkts.buffer.Buffer; import io.pkts.packet.IPPacket; import io.pkts.packet.Packet; import io.pkts.protocol.Protocol; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import java.util.List; /** * @Description TODO * @Author silence.Z * @Date 2020/10/20 15:00 * @Version 1.0 **/ @Component @Order(value = 1) public class DeviceRunner implements ApplicationRunner { @Autowired private DeviceService deviceService; private static String logPath = "/home/ganinfo/logs/pacp.log"; //private static String logPath = "D:\\pacp.log"; @Override public void run(ApplicationArguments args) throws Exception { Pcap pcap = null; try { //读取解析pcap文件 //pcap = Pcap.openStream("d:\\dump3615.pcap"); pcap = Pcap.openStream("/home/ganinfo/dump3615.pcap"); while (true) { try { pcap.loop((final Packet packet) -> { if (packet.hasProtocol(Protocol.TCP)) { //获取pcap文件中的tcp协议包 Buffer payload = packet.getPacket(Protocol.TCP).getPayload(); //根据协议包获取IPV4地址 IPPacket ip = (IPPacket) packet.getPacket(Protocol.IPv4); String sourceIP = ip.getSourceIP(); //获取tcp协议包中的摄像机向ftp服务器发送的图片名称并对其进行截取,获得设备编号 if (payload != null && payload.toString().contains("STOR")) { String devicecode = payload.readLine().toString().substring(5, 13); LogUtils.log(logPath, sourceIP + "," + devicecode); //查询数据库是否存在该设备号的摄像机 List<Device> devices = deviceService.selectByCode(devicecode); Device device = devices.get(0); String publicip = device.getPublicip(); //如果数据库存在唯一摄像机且数据库中获取到的公网IP与根据协议包获取到的IPV4地址不相同 if (devices.size() == 1 && !device.getPublicip().equals(sourceIP)){ //更新数据库,将数据库中所有公网IP相同的数据进行更新 device.setPublicip(sourceIP); int i = deviceService.updateDevice(device,publicip); if (i > 0){ LogUtils.log(logPath,"摄像机"+devicecode+"公网IP发生变动,数据库中所有与其公网IP相同的设备更新成功! 原IP为:" + publicip + ",现IP为:" + sourceIP + ",更新的设备数量为:" + i); }else { LogUtils.log(logPath,"!!!!!!!!!!!摄像机"+devicecode+"公网IP发生变动,更新失败! 原IP为:" + publicip + ",现IP为:" + sourceIP + ",更新的设备数量为:" + i); } } System.out.println(sourceIP + "," + devicecode); } } return true; }); //每隔5秒解析一次协议包,之后建议加长 Thread.sleep(1000 * 5); } catch (Exception e) { e.printStackTrace(); } } } catch (Exception e) { e.printStackTrace(); } } }

3.为了查看日志方便,编写了LogUtils工具类。

public class LogUtils { public static void log(String logPath, String msg) { OutputStream out = null; OutputStreamWriter ow = null; BufferedWriter bw = null; SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String time = df.format(new Date()); msg = time + " " + msg; File newFile = null; try { newFile = new File(logPath); if (!newFile.exists()) { newFile.createNewFile(); } out = new BufferedOutputStream(new FileOutputStream(newFile, true)); ow = new OutputStreamWriter(out, "utf-8"); bw = new BufferedWriter(ow); bw.write(msg); bw.newLine(); bw.flush(); } catch (IOException var9) { var9.printStackTrace(); } } }

五、打包发布到服务器。 1.点击idea下方的“Terminal”再通过mvn clean install 命令进行打包。 2.上传到服务器,通过java -jar jar包名命令进行运行,查看logPath路径下的日志,成功。 若需要完整代码或有更好的解决方案,欢迎评论区留言!

最新回复(0)