内网穿透实现基于树莓派的网络摄像头

树莓派网络摄像头内网穿透

前言: 上一篇博客已经提到了我自己买了一个树莓派摄像头,搭建了一个局域网监控系统。但是这个东西不能在外网访问的话,它是实际应用价值就很低了。因为当时选择的钉钉内网穿透方式不能使用(指令集不兼容),所以我就暂时放弃了,转而思考了使用自己的网络编程知识来模拟实现一下内网穿透的效果。然后,我的同学给我提出了建议,要是可以使用流媒体就更好了(实际上我也不会流媒体,不过我倒是有一点兴趣)。我于是在当时的代码基础上,又进行了改进,专门针对motion实现的局域网监控方式,重新写了一个代码,希望可以实现外网访问motion中的内网。

一、项目

1.演示视频

内网穿透实现基于树莓派的网络摄像头

2.代码

代码已经上传到了github,通过下面链接可以访问到。
raspberry_monitor

二、结构设计

说明:这里我的PC部分可以不需要,因为我是在PC上运行的客户端代码,所以就捎带上了。
架构设计

三、代码设计

设计思路

主要设计思路参考上一篇博客:黑盒方式模拟实现内网穿透
这里只做一个简要介绍了:
在阿里云和树莓派之间维持两个长连接,其中一个用来进行通信控制,另一个用来进行数据传输。对于访问阿里云的请求 ,通过该通信控制长连接进行中转,将请求发给树莓派,同时将响应数据通过数据传输长连接返回给阿里云服务器,再由阿里云服务器响应给用户。

内网穿透思路

这里将控制通信的长连接称为中间人,进行数据传输的长连接称为管道。并且由中间人控制管道的开启和关闭。由于管道只有一条,所以这里只能允许一个用户进行访问。对于其它的用户,要禁止其进行访问。因为多个中间人和管道设计比较麻烦(我不会,哈哈!),我这里只能实现一个中间人和一个管道的方式,并且多个用户访问,对树莓派和服务器的压力都比较大,也不是很适合(这是一个借口,主要还是能力不够)。

启动方式

1.首先启动服务器,注意此时不能访问服务器,否则项目无法工作。
2.然后启动客户端,客户端会立刻和服务器建立上面说的两个连接,等待服务器打印出建立成功的消息后,用户才可以进行正常访问。

注意:之所以必须严格这种顺序是因为我这里其实是混合使用了几种协议(长连接算是自己自定义的协议),但是我并没有去分辨这几种协议,只是默认先连接的是树莓派和服务器的长连接,后连接的才是和服务器的HTTP连接。总之,就是因为太复杂了,所以我使用了简单的方式,毕竟能运行才是真道理!

四、代码实现

工程目录

在这里插入图片描述

服务器端代码

NetServer

package org.dragon;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class NetServer {
   
   
	
	private static final int THREAD = 3;
	
	public static void main(String[] args) {
   
   
		int port = 10000;  // 默认端口号
		try {
   
   
			port = Integer.parseInt(args[0]);
		} catch (Exception e) {
   
   
		//	e1.printStackTrace();
		}
		
		System.out.println("服务器启动中,占用端口为:" + port);
		
		ExecutorService threadPool = Executors.newFixedThreadPool(THREAD);
		Lock lock = new ReentrantLock();
		
		try (ServerSocket server = new ServerSocket(port)) {
   
   
			// 传输数据的管道
			Socket pipeline = server.accept();
			System.out.println("数据传输管道建立成功。。。");
			// 控制管道的中间人
			Socket middleman = server.accept();
			System.out.println("中间人建立成功。。。");
			System.out.println("系统启动。。。");
			// 下面是作为一个Http服务器的部分了。
			while (true) {
   
   
				Socket client = server.accept();
				System.out.println("一个请求进入系统。。。" + client);
				threadPool.submit(new UserConnection(client, 
						new PipelineServer(pipeline), 
						new MiddlemanServer(middleman),
						lock));
			}
		} catch (IOException e) {
   
   
			e.printStackTrace();
		}	
	}
	
}

MiddlemanServer

package org.dragon;

import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;

/**
 * 用于协调双方通信的中间人
 * */
public class MiddlemanServer {
   
   

	private DataOutputStream output;
	
	public MiddlemanServer(Socket middleman) throws IOException {
   
   
		this.output = new DataOutputStream(new BufferedOutputStream(middleman.getOutputStream()));
	}

	/**
	 * 建立一个连接
	 * @throws IOException 
	 * */ 
	public void open() throws IOException {
   
   
		output.writeChar('Y');<
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值