天天看点

实现通过公网远程访问运行在服务器上的Python程序

前言

前段时间学习了HTTP的原理,并用Python语言实现了一个简单的HTTP服务器(带有多线程功能的哦);后面突发一想,我能把挂在本地服务器上,每次运行都需要打开虚拟机并运行程序(这样真的很麻烦)。我想起之前阿里云服务器打折的时候,也跟随着小伙伴一起入手了一个最低配的,之前这个服务器只是用来刷票的,现在终于能发挥他的作用了。

准备

1、程序

简单描述:我这个程序是能通过浏览器,访问程序并通过服务器上的资源路径把资源返回给浏览器并呈现出来,下面是这个程序的源码:

# 实现步骤:
#
# 编写一个TCP服务端程序
# 获取浏览器发送的http请求报文数据
# 读取固定页面数据,把页面数据组装成HTTP响应报文数据发送给浏览器。
# HTTP响应报文数据发送完成以后,关闭服务于客户端的套接字。


#1.导入模块
import socket
import threading
from urllib import request
import sys

# 注意,这段代码必须在命令行中运行。

# 实现步骤:
#
# 把提供服务的Web服务器抽象成一个类(HTTPWebServer)
# 提供Web服务器的初始化方法,在初始化方法里面创建socket对象
# 提供一个开启Web服务器的方法,让Web服务器处理客户端请求操作。
class WebServer(object):
    def __init__(self):
        # 2.创建socket对象
        tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        # 设置地址复用
        tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
        # 3.绑定端口号
        tcp_server_socket.bind(("", 3389))
        # 4.设置监听模式
        tcp_server_socket.listen(100)
        # 设置一个实例属性
        self.tcp_server_socket = tcp_server_socket


    def start(self):
        while True:
            # 5.等待客户端的链接(返回新的socket)
            new_service_client, client_address_info = self.tcp_server_socket.accept()
            print("客户端链接: ", client_address_info)

            # handler_client(new_service_client)
            # 一旦有客户端链接,我们就创建一个新的子线程服务客户端
            sub_thread = threading.Thread(target=self.handler_client, args=(new_service_client,))
            # 设置子线程为守护线程,主线程结束时,所有守护线程也结束
            sub_thread.setDaemon(True)
            # 启动子线程
            sub_thread.start()

    # 实例方法:对象方法 (self)
    # def handler_client(self, new_service_client):

    # 类方法: (cls)

    # 静态方法
    @staticmethod
    def handler_client(new_service_client):

        # 6.接收浏览器发送的数据(请求报文)
        recv_data = new_service_client.recv(4096)
        if len(recv_data) == 0:
            print("浏览器关闭(客户端下线)")
            new_service_client.close()
            return
        print(recv_data)
        recv_content = recv_data.decode("utf-8")
        print("请求报文: ", recv_content)
        #   6.1 解析请求报文获取资源路径
        #       GET /index.html HTTP/1.1
        #       按照空格分割,最多分割两次
        recv_list = recv_content.split(" ", maxsplit=2)
        #   6.2 获取资源路径
        #       file_path = xxx[1]
        file_path = recv_list[1]
        print(file_path)

        # 判断file_path是否是/, 指向首页index.html
        if file_path == "/":
            file_path = "/index.html"
		# 因为资源路径包含中文,浏览器发送请求时会用utf-8的方式对包含中文的资源路径进行编码,所以若包含中文需要先解码
        file_path = request.unquote(file_path)
        print(file_path)
        try:
            # 7.放送数据给浏览器
            #   7.1 打开指定页面文件(static + file_path)
            # 打开的文件找不到,会抛出异常
            with open("notes" + file_path, "rb") as file:
                file_data = file.read()

        except Exception as e:
            # 资源路径找不到

            #   7.1 打开指定页面文件(static + file_path)
            with open("notes/error.html", "rb") as file:
                file_data = file.read()

            #   7.2 拼接成响应报文数据
            #       响应行
            response_line = "HTTP/1.1 404 Not Found\r\n"
            #       响应头
            response_head = "Server: NBW/1.0\r\n"
        else:
            # 找到资源路径
            #   7.2 拼接成响应报文数据
            #       响应行
            response_line = "HTTP/1.1 200 OK\r\n"
            #       响应头
            response_head = "Server: NBW/1.0\r\n"
            #       空行
            #       \r\n

        #       响应体
        response_body = file_data

        response_data = (response_line + response_head + "\r\n").encode("utf-8") + response_body
        #   7.3 发送数据给浏览器
        new_service_client.send(response_data)
        # 8.关闭链接
        new_service_client.close()

def main():
    w1 = WebServer()
    # 启动w1
    w1.start()

if __name__ == '__main__':
    main()

           

2、服务器

我这里准备的是阿里的服务器,

Ubuntu 16.04.6 LTS (GNU/Linux 4.4.0-142-generic x86_64)

实现通过公网远程访问运行在服务器上的Python程序

过程

1、通过ssh服务把python文件和资源文件上传到服务器的指定目录中(自己得记住),我这里是放在Desktop上的。

实现通过公网远程访问运行在服务器上的Python程序

2、通过

python3 07-web静态服务器-返回指定页面-多任务版本-面向对象编程......py

把这个程序运行起来,在本地的浏览器通过公网ip+端口发现无法访问。

注:确保程序调用的端口已经对外公开了,我这里设置的端口是:3389

实现通过公网远程访问运行在服务器上的Python程序

3、把端口号设置好后,再启动程序,再通过本地浏览器访问(我的ip+port:http://47.107.138.151:3389),发现资源可以访问已经配置好的资源了。

实现通过公网远程访问运行在服务器上的Python程序

4、把cmd窗口关闭之后,会发现刚刚运行的程序停了,刚刚的资源又无法访问了;下面介绍一种

# *.py是你的py文件名
nohup python *.py &
           

这里有更详细的介绍在服务器端,如何一直运行你的python代码

继续阅读