ORAY 민들레 원격 네트워킹을 사용하여 Raspberry Pi 원격 SSH 액세스 실현
요약
- 나는 회사와 집에서 디버깅하고 개발할 수 있기를 바라며 Raspberry Pi 4B로 시작했습니다.
- 회사와 가정에는 공용 네트워크 IP가 없으므로 (통신 방식을 사용하는 것이 좋습니다) 공용 네트워크에서 Raspberry Pi에 액세스할 방법이 없습니다.
- 가상 머신 개발 환경의 준비가 너무 번거롭고 닭을 죽이는 것은 큰 망치입니다.
- 나는 매일 보드를 가지고 앞뒤로 달리고 싶지 않습니다.
필요
- 전원 켜짐
- 부팅 후 인터넷 연결 여부 감지(스크립트 자동 실행)
- 네트워크 연결이 성공적인지 확인한 후 Dandelion에 로그인합니다(자동으로 스크립트 실행).
- 네트워킹 후 LAN IP 주소로 메일을 보냅니다(파이썬 파일 자동 실행).
- Dandelion을 통한 원격 네트워킹을 통해 Raspberry Pi에 액세스합니다.
준비(중요)
- Raspberry Pi가 ssh를 엽니다.
- WiFi 자동 연결 설정;
- Dandelion을 설치하고 자동 로그인을 설정하십시오.
- 스마트 소켓.
공식적으로 시작
1단계: Dandelion 서비스를 시작하는 스크립트 만들기
pgyvpnservice.sh 스크립트를 생성하여 /home/pi/Desktop 디렉터리에서 Dandelion 서비스를 시작합니다.
#!/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
2단계: 네트워크 감지 스크립트 만들기
/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
3단계: 시작 항목 구성
네트워크 연결을 감지하기 위해 부팅을 구현하고 네트워크 연결이 정상인 후 Dandelion을 실행하십시오.
- rc.local 파일을 편집합니다.
sudo nano /etc/rc.local
- exit0 전에 입력:
nohup /etc/init.d/network_test.sh & #后台启动网络检测脚本
4단계: LAN IP 주소를 지정된 사서함으로 자동 전송
목적 :
- 할당된 IP 주소를 보기 위해 라우터에 로그인할 수 없을 때 Raspberry Pi의 위치를 파악합니다.
- 이메일을 받은 후 Raspberry Pi가 인터넷에 연결되고 Dandelion이 성공적으로 열렸음을 확인할 수 있습니다. 이를 통해 공용 네트워크 액세스를 실현할 수 있습니다(이 단계는 Dandelion 콘솔 또는 클라이언트를 통해서도 수행할 수 있지만 캐시로 인한 문제는 및 기타 문제는 이메일을 통해 효과적으로 피할 수 있습니다).
- Raspberry Pi 주소를 가져오고 이메일을 보내려면 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())
- ip_address.py를 /home/pi/Desktop에 복사합니다.
- 부팅 시 시작되도록 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
5단계: 이메일을 통해 Raspberry Pi에 명령 전송 실현
- command_trans.py는 비상 시 이메일을 통해 Raspberry Pi 터미널과 제한된 임시 통신을 수행할 수 있습니다.
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)
- command_trans.py를 /home/pi/Desktop에 복사합니다.
- 부팅 시 시작하도록 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
6단계: 전원을 켜고 시작한 다음 Dandelion 서비스가 온라인 상태가 될 때까지 기다립니다.
스마트 소켓을 사용하여 전원을 원격으로 제어하고, 전원을 켠 후 네트워크 상황에 따라 일정 시간 동안 대기한 후 LAN IP 주소 이메일을 받거나(권장) 라즈베리 파이가 로그인되어 있고 ping이 가능한지 확인합니다. Dandelion 콘솔/클라이언트, 즉 Dandelion에서 할당한 IP 주소를 통해 공용 네트워크를 통해 액세스할 수 있습니다.
지침
- 사전에 준비 항목의 모든 작업을 완료하십시오. Dandelion은 자동 로그인이 실행될 수 있는지 확인해야 합니다. 그렇지 않으면 스크립트가 서비스를 시작할 수 없습니다.
- rc.local 파일에서 시작 항목의 순서에 주의하십시오 순서가 잘못되면 시작 항목이 정상적으로 시작되지 않을 수 있습니다.
- 첨가되는.