2019年4月

近期,由于在外面实习,但是毕业设计所使用的树莓派开发板还静静躺在我的宿舍之中,为了能够每天下班也能做我的毕业设计,特地去搜索了一些关于内网穿透的东西,发现了GitHub上一个开源的内网穿透工具---frp,经过短暂的学习之后,终于实现了能够远程ssh和vnc到我的树莓派。

内网穿透

内网穿透即NAT穿透,网络连接时术语,计算机是局域网内时,外网与内网的计算机节点连接通信

准备工作

  • 具有公网IP的vps
  • 树莓派可上外网

frp

  • 项目地址:https://github.com/fatedier/frp
  • 项目功能:实现内网穿透,原理为端口映射与流量转发
  • 具体功能实现:远程ssh远程vnc远程web等等

配置

1.服务器端配置

# 远程以root用户登陆你的vps

# 下载frp
wget https://github.com/fatedier/frp/releases/download/v0.25.3/frp_0.25.3_linux_amd64.tar.gz

# 解压
tar -zxvf frp_0.25.3_linux_amd64.tar.gz

# 编辑配置文件
vim frp_0.25.3_linux_amd64/frps.ini

########
[common]
bind_port = 8000
########

# 将以上内容添加至配置文件中,bind_port 是frp客户端与服务器连接的端口,需要在你的vps开放权限

# 编辑服务文件
vim /lib/systemd/system/frp.service

######################################
 [Unit]
Description=frp service
After=network.target syslog.target
Wants=network.target

[Service]
Type=simple
ExecStart=/root/frp_0.25.3_linux_amd64/frps -c /root/frp_0.25.3_linux_amd64/frps.ini

[Install]
WantedBy=multi-user.target
######################################

# 将以上内容添加至配置文件中,保存退出

################################
systemctl start frp   # 启动frp服务
systemctl restart frp # 重启frp服务
systemctl enable frp  # 将frp加入开机启动项
systemctl status frp  # 查看frp服务状态
################################

2.客户端配置

# 登陆你的树莓派

# 下载frp
wget https://github.com/fatedier/frp/releases/download/v0.25.3/frp_0.25.3_linux_arm.tar.gz

# 解压
tar -zxvf frp_0.25.3_linux_arm.tar.gz

# 编辑配置文件
vim frp_0.25.3_linux_amd64/frpc.ini

################################
[common]
server_addr = 104.243.24.56
server_port = 8000 #这个端口必须跟服务器的一样
 
[ssh]
type = tcp 
local_ip = 127.0.0.1
local_port = 22
remote_port = 6000 #这个端口自行设置,需要vps开启这个端口的权限
 
[vnc]
type = tcp 
local_ip = 127.0.0.1
local_port = 5900
remote_port = 6001 #这个端口自行设置,需要vps开启这个端口的权限
################################

# 将以上内容添加至配置文件中

# 编辑服务文件
vim /lib/systemd/system/frp.service

######################################
 [Unit]
Description=frp service
After=network.target syslog.target
Wants=network.target

[Service]
Type=simple
ExecStart=/home/pi/frp_0.25.3_linux_arm/frpc -c /home/pi/frp_0.25.3_linux_arm/frpc.ini

[Install]
WantedBy=multi-user.target
######################################

# 将以上内容添加至配置文件中,保存退出

################################
systemctl start frp   # 启动frp服务
systemctl restart frp # 重启frp服务
systemctl enable frp  # 将frp加入开机启动项
systemctl status frp  # 查看frp服务状态
################################

享用

  • 连接ssh:ssh -oPort=6000 pi@vps的ip地址
  • 连接vnc:用vnc客户端连接vps的ip地址:6001

基本概念

  • 逆波兰式:用比较通俗的语言来讲,就是将多项式的操作数和符号重新排列,操作数在前,符号在后
  • 栈:这种数据结构是一种特殊的线性表,只能在一头进行插入和删除,所以有着先进后出的特点

算法实现

  • 中缀式转逆波兰式

需要一个符号栈,初始为空,遍历多项式的每项,如果是数字,记录进结果,如果是符号,判断当前符号和栈顶符号的优先级(括号 < + - < * /),如果优先级大于栈顶符号,则进栈;如果优先级小于栈顶符号,栈顶出栈,如果出栈的不是括号,记录至结果中,直至栈顶优先级小于当前符号,而后符号进栈,直至遍历完整个表达式,最后将符号栈中的符号出栈记录至结果

  • 计算逆波兰式

需要一个结果栈,初始为空,遍历逆波兰式,如果是数字,进栈,遇到符号,出栈两个操作数,进行计算并将计算结果进栈,直至遍历完成,此时栈顶为表达式结果

代码实现

stack.py

import readline
import time
expression = input("请输入表达式(每个字符用空格隔开):")
expression = expression.split()

def get_Reverse_Polish_Notation(expression):
    '''转化逆波兰式'''
    stack = list()
    result = list()
    symbol = ['(', ')', '+', '-', '*', '/']
    value = {
        '(':1,
        ')':1,
        '+':2,
        '-':2,
        '*':3,
        '/':3,
    }
    for i in expression:
        #如果元素是数字,直接进栈
        if i.isdigit():
            result.append(i)
        #如果元素是符号,进入判断
        if i in symbol:
            #如果栈不为空,则判断符号优先级
            if stack:
                #判断如果符号优先级不高于栈顶符号优先级,则出栈,直至优先级大于栈顶符号
                if value[i] <= value[stack[-1]] and i != '(':
                    #如果符号为右括号,则进行匹配左括号
                    if i == ')':
                        while stack[-1] != '(':
                            result.append(stack.pop())
                        stack.pop()
                    #如果不是右括号,则进行出栈操作,直到大于栈顶符号为止
                    else:
                        while True:
                            result.append(stack.pop())
                            if stack:
                                if value[i] > value[stack[-1]] :
                                    stack.append(i)
                                    break
                            else:
                                    stack.append(i)
                                    break

                #如果大于栈顶符号,直接进栈
                else:
                    stack.append(i)
            #如果初始栈为空,则直接进栈第一个符号
            else:
                stack.append(i)
    #遍历完整个表达式,将栈中剩余的符号出栈
    while stack:
        result.append(stack.pop())
    #返回结果列表
    return result

def count_result(result):
    '''计算逆波兰式'''
    stack = list()
    #遍历逆波兰式,如果是数字,直接进栈,如果是符号,则出栈两个操作数,计算出结果入栈
    for i in result:
        if i.isdigit():
            stack.append(i)
        else:
            if i == '+':
                temp = float(stack[-2]) + float(stack[-1])
                stack.pop()
                stack.pop()
                stack.append(str(temp))
            elif i == '-':
                temp = float(stack[-2]) - float(stack[-1])
                stack.pop()
                stack.pop()
                stack.append(str(temp))
            elif i == '*':
                temp = float(stack[-2]) * float(stack[-1])
                stack.pop()
                stack.pop()
                stack.append(str(temp))
            elif i == '/':
                temp = float(stack[-2]) / float(stack[-1])
                stack.pop()
                stack.pop()
                stack.append(str(temp))
    return float(stack[-1])