使用ORAY蒲公英异地组网实现树莓派异地SSH访问

前情提要

  1. 上手了一块树莓派4B,希望能够在公司和家里都能调试开发;
  2. 公司和家里没有公网IP(所以说还是电信大法好),没办法实现公网访问树莓派;
  3. 虚拟机开发环境准备太麻烦,杀鸡用牛刀;
  4. 不愿意每天带着板子来回跑。

需求

  1. 上电开机
  2. 开机后检测是否联网(自动执行脚本);
  3. 确认网络连接成功后登录蒲公英(自动执行脚本);
  4. 联网后邮件发送局域网IP地址(自动执行python文件);
  5. 通过蒲公英实现异地组网访问树莓派。

准备项(重要)

  1. 树莓派开启ssh;
  2. 设置WiFi自动连接;
  3. 安装蒲公英并设置好自动登录;
  4. 智能插座。

正式开始

第一步:创建启动蒲公英服务脚本

在/home/pi/Desktop目录下创建启动蒲公英服务脚本pgyvpnservice.sh:

#!/bin/sh
#/etc/init.d/pgyvpnservice.sh
### BEGIN INIT INFO
# Provides:testboot
# Required-Start:$remote_fs $syslog
# Required-Stop:$remote_fs $syslog
# Default-Start:2 3 4 5
# Default-Stop:0 1 6
# Short-Description: testboot
# Description: This service is used to start my applaction
### END INIT INFO
case "$1" in
  start)
    echo "启动蒲公英异地组网"
    su root -c "pgyvpn"	# 以root模式执行pgyvpn指令打开蒲公英
  ;;
  stop)
    echo "执行完毕"
  ;;
esac

第二步:创建网络检测脚本

在/etc/init.d目录下创建网络检测脚本network_test.sh:

#!/bin/bash
#检测网络链接&&ftp上传数据
declare -i n=0	#创建变量n并声明为数值
while [ $n -ne 1 ]	#判断n是否不等于1
do
	ret_code=`curl -I -s --connect-timeout 5 baidu.com -w %{
    
    http_code} | tail -n1`	#网络值
	if [ "$ret_code" = "200" ]; then
		nohup /home/pi/Desktop/pgyvpnservice.sh &	#网络连接成功后需要启动的程序脚本,即pgyvpnservice.sh
		n=1;
	else
		n=0; #失败等待
	fi
done

第三步:配置开机启动项

实现开机检测网络连接,网络连接正常后运行蒲公英。

  1. 编辑rc.local文件:
sudo nano /etc/rc.local
  1. 在exit0前输入:
nohup  /etc/init.d/network_test.sh &	#后台启动网络检测脚本

第四步:自动将局域网IP地址发送至指定邮箱

目的

  • 当无法登录路由器查看分配的IP地址时,了解树莓派所在位置。
  • 收到邮件即可确认树莓派已联网并顺利开启蒲公英,可以实现公网访问(这一步通过蒲公英控制台或客户端也可以实现,但通过邮件可以有效避免缓存等问题带来的困扰)。
  1. 编写ip_address.py,用于获取树莓派地址并发送邮件:
# -*- coding: utf-8 -*-
from multiprocessing import connection
import socket
import smtplib
import time
import socket

# 分割线内部分为网络检测,如在树莓派设置网络检测脚本,本部分可省略
# ------------------------------------------------------------------
# 测试网络连接情况
def isNetOK(testserver):
    s=socket.socket()
    s.settimeout(3)
    try:
        status = s.connect_ex(testserver)
        if status == 0:
            s.close()
            return True
        else:
            return False
    except Exception as e:
        return False
# 测试百度是否可以访问
def isNetChainOK(testserver=('www.baidu.com',443)):
    isOK = isNetOK(testserver)
    return isOK
if __name__ == '__main__':
    connection_attempt=True
    while connection_attempt:
        chinanet = isNetChainOK()
        if chinanet==True:
            break
# ------------------------------------------------------------------

# 邮件发送方邮箱地址
MAIL_USER = ''
# MAIL_PASS要使用授权码而非密码
MAIL_PASS = ''
# 邮箱stmp服务器地址
SMTP_SERVER = ''
SMTP_PORT = 25
# 邮件接收方邮箱地址
recipient1=''
# 邮件主题
subject1 = 'ip_address'
#获取IP地址
def get_host_ip():
    try:
        s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
        s.connect(('8.8.8.8',80))
        ip = s.getsockname()[0]
    finally:
        s.close()
    return ip

def send_mail(input_text):
    text = input_text
    
    smtpserver = smtplib.SMTP(SMTP_SERVER,SMTP_PORT)
    smtpserver.ehlo()
    smtpserver.starttls()
    smtpserver.ehlo
    smtpserver.login(MAIL_USER,MAIL_PASS)
    
    header = 'To:'+recipient1+'\n'+'From:'+MAIL_USER
    header = header + '\n' +'Subject:' + subject1 +'\n'
    timeStr = time.strftime(' %Y_%m_%d %H:%M:%S',time.localtime(time.time()))
    msg = header +'\n'+text+'\n'+timeStr+'\n\n'
    smtpserver.sendmail(MAIL_USER,recipient1,msg)
    smtpserver.close()

time.sleep(10)
send_mail(get_host_ip())
  1. 将ip_address.py复制到/home/pi/Desktop。
  2. 将ip_address.py设置为开机启动:
# 编辑rc.local文件
sudo nano /etc/rc.local
# 在exit0前、nohup  /etc/init.d/network_test.sh &后输入:
sudo python /home/pi/Desktop/ip_address.py

第五步:实现通过邮件向树莓派发送指令

  1. command_trans.py可通过邮件方式与树莓派终端进行有限的临时通讯,以备不时之需:
import os
import datetime
from calendar import TextCalendar
from cgitb import text
from operator import truediv
import poplib
import base64
from email.parser import Parser
from email.header import decode_header
from email.utils import parseaddr
from time import sleep
import smtplib
from email import encoders
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from unittest import result

def get_email_content():
	useraccount = ''
	password = ''

	# 邮件服务器地址,以下为网易邮箱
	pop3_server = 'pop.163.com'

	# 开始连接到服务器
	server = poplib.POP3(pop3_server)

	# 打开或者关闭调试信息,为打开,会在控制台打印客户端与服务器的交互信息
	server.set_debuglevel(0)

	# 打印POP3服务器的欢迎文字,验证是否正确连接到了邮件服务器
	# print(server.getwelcome().decode('utf8'))

	# 开始进行身份验证
	server.user(useraccount)
	server.pass_(password)

	# 返回邮件总数目和占用服务器的空间大小(字节数), 通过stat()方法即可
	email_num, email_size = server.stat()
	# print("消息的数量:{0}, 消息的总大小:{1}".format(email_num, email_size))

	# 使用list()返回所有邮件的编号,默认为字节类型的串
	rsp, msg_list, rsp_siz = server.list()
	# print("服务器的响应: {0},\n消息列表: {1},\n返回消息的大小: {2}".format(rsp, msg_list, rsp_siz))

	# print('邮件总数:{}'.format(len(msg_list)))

	# 获取最新的一封邮件
	total_mail_numbers = len(msg_list)
	rsp, msglines, msgsiz = server.retr(total_mail_numbers)
	# print("服务器的响应: {0},\n原始邮件内容: {1},\n该封邮件所占字节大小: {2}".format(rsp, msglines, msgsiz))

	msg_content = b'\r\n'.join(msglines).decode('gbk')
	# 邮件信息(未解码)
	msg = Parser().parsestr(text=msg_content)
	# print('解码后的邮件信息:\n{}'.format(msg))
	# 关闭与服务器的连接,释放资源
	server.close()

	return msg

# 用来解析邮件主题 
def parser_subject(msg):
	subject = msg['Subject']
	value, charset = decode_header(subject)[0]
	if charset:
		value = value.decode(charset)
	# print('邮件主题:{0}'.format(value))
	return value

# 用来解析邮件来源 
def parser_address(msg):
	hdr, addr = parseaddr(msg['From'])
	# name 发送人邮箱名称, addr 发送人邮箱地址
	name, charset = decode_header(hdr)[0]
	if charset:
		name = name.decode(charset)
	# print('发送人邮箱地址: {0}'.format(addr))
	return addr

def parser_content(msg):
	content = msg.get_payload()
	# 文本信息
	content_charset = content[0].get_content_charset() # 获取编码格式
	text = content[0].as_string().split('base64')[-1]
	text_content = base64.b64decode(text).decode(content_charset) # base64解码
 
	# 添加了HTML代码的信息
	# content_charset = content[1].get_content_charset()
	# text = content[1].as_string().split('base64')[-1]
	# html_content = base64.b64decode(text).decode(content_charset)
 
	# print('文本信息: {0}'.format(text_content))
	return text_content

def send_email(command, execution_feedback):
	# sender是邮件发送人邮箱,pw是服务器授权码,mail_host是服务器地址
	sender = ''
	pw = ''
	mail_host = ''
	# receivers是邮件接收人,用列表保存,可以添加多个
	receivers = ['']

	# 设置email信息
	msg = MIMEMultipart()
	time_stamp = '{0:%Y-%m-%d-%H-%M}'.format(datetime.datetime.now())
	# 邮件主题
	msg['Subject'] = command + ' -- Execution result -- '+time_stamp
	# 发送方信息
	msg['From'] = sender
	# 邮件正文是MIMEText:
	msg_content = execution_feedback
	msg.attach(MIMEText(msg_content, 'plain', 'utf-8'))

	# 登录并发送邮件
	try:
		#QQsmtp服务器的端口号为465或994
		s = smtplib.SMTP_SSL(mail_host, 465)
		s.set_debuglevel(1)
		s.login(sender,pw)
		#给receivers列表中的联系人逐个发送邮件
		for item in receivers:
			msg['To'] = to = item
			s.sendmail(sender,to,msg.as_string())
			print('Success!')
		s.quit()
		# print ("All emails have been sent over!")
	except smtplib.SMTPException as e:
		print ("Falied,%s",e)

if __name__ == '__main__':
	# 返回解码的邮件详情
	msg = get_email_content()
	# 解析邮件主题
	value=parser_subject(msg)
	# 解析发件人详情
	addr=parser_address(msg)
	# 解析内容
	text_content=parser_content(msg)
	# 保证每次开机读取邮件时不会被已有邮件干扰
	command_line=text_content
	send_email('设备已开机,网络连接正常,已准备好通过邮件接收指令。', '最新一封邮件内容:'+text_content)
	while True:
		# 返回解码的邮件详情
		msg = get_email_content()
		# 解析邮件主题
		value=parser_subject(msg)
		# 解析发件人详情
		addr=parser_address(msg)
		# 解析内容
		text_content=parser_content(msg)
		if text_content!=command_line:
			command_line=text_content
			statement_execution = os.popen(command_line.replace('\n', '').replace('\r', ''))
			feedback_line = statement_execution.read()
			send_email(command_line,feedback_line)
		else:
			pass
		# 每间隔5分钟进行一次邮件收发
		sleep(300)
  1. 将command_trans.py复制到/home/pi/Desktop。
  2. 将command_trans.py设置为开机启动:
# 编辑rc.local文件
sudo nano /etc/rc.local
# 在exit0前、sudo python /home/pi/Desktop/ip_address.py &后输入:
sudo python /home/pi/Desktop/command_trans.py

第六步:上电开机,等待蒲公英服务上线

使用智能插座远程控制上电,上电后视网络情况等待一段时间,收到局域网IP地址邮件(推荐)或在蒲公英控制台/客户端上看到树莓派端已登录并能够ping通,即可通过蒲公英分配的IP地址进行公网访问。

注意事项

  1. 提前完成准备项内各项工作,蒲公英要保证自动登录能够执行,否则脚本无法开启该服务。
  2. 务必关注rc.local文件中启动项顺序,顺序错误可能导致后面启动项无法正常启动。
  3. 待补充。

猜你喜欢

转载自blog.csdn.net/m0_37728676/article/details/108513568