python单进程Web服务器案例

作者: 鲁智深 分类: Python 发布时间: 2017-12-30 01:14

Web静态服务器-1-显示固定的页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
from socket import socket,AF_INET,SOL_SOCKET,SOCK_STREAM,SO_REUSEADDR#导入套接字需要的内容
from multiprocessing import Process#开启进程

def http_recv(new_socket):#接收数据函数
    recv_data = new_socket.recv(1024)#单次接收数据的最大值
    print(recv_data)
   
    response_statr = "HTTP1.1 200 OK\r\n"#响应行
    response_header = "Content-Type: text/html; charset=utf-8\r\n"#响应头
    response_space = "\r\n"#空行
    response_body = "我来自服务器"#响应体
    response = response_statr + response_header + response_space + response_body#响应内容拼接
    new_socket.send(response.encode("utf-8"))#发送发浏览器

def main():
    http_socket = socket(AF_INET,SOCK_STREAM)#创建套接字
    http_socket.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)#端口重用
    http_socket.bind(("",9999))#绑定端口
    http_socket.listen(128)#监听,并接收链接

    try:
        while True:
            new_socket,new_address = http_socket.accept()#返回新的套接字
            print("新用户进来了",new_address)
            Process(target=http_recv,args=(new_socket,)).start()#开启进程,传入参数函数名和新的套接字
            new_socket.close()#关闭套接字
    except:
        http_socket.close()#捕获异常,出现异常关闭套接字

if __name__ == '__main__':
    main()
请求报文

请求报文

响应报文

响应报文

浏览器效果

浏览器效果

Web静态服务器-2-显示需要的页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
from socket import socket,AF_INET,SOL_SOCKET,SOCK_STREAM,SO_REUSEADDR
from multiprocessing import Process
import re

HTTP_ROOT_DIR = "./html"

def http_recv(new_socket):
    recv_data = new_socket.recv(1024)
    request_lins = recv_data.splitlines()#根据按照行('\r', '\r\n', \n')分隔
    request_data = re.match(r"\w+ +(/[^ ]*)",request_lins[0].decode("utf-8"))#正则取第一个括号里的内容
    file_name = request_data.group(1)

    if "/index.html" == file_name:
        f = open(HTTP_ROOT_DIR + file_name,"r")
        request = f.read()
        f.close()

    if "/" == file_name:
        f = open(HTTP_ROOT_DIR + "/index.html", "r")
        request = f.read()
        f.close()

    response_statr = "HTTP1.1 200 OK\r\n"
    response_header = "Content-Type: text/html; charset=utf-8\r\n"
    response_space = "\r\n"
    response_body = request
    response = response_statr + response_header + response_space + response_body
    new_socket.send(response.encode("utf-8"))

def main():
    http_socket = socket(AF_INET,SOCK_STREAM)
    http_socket.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
    http_socket.bind(("",9999))
    http_socket.listen(128)

    try:
        while True:
            new_socket,new_address = http_socket.accept()
            print("新用户进来了",new_address)
            Process(target=http_recv,args=(new_socket,)).start()
            new_socket.close()
    except:
        http_socket.close()

if __name__ == '__main__':
    main()

index.html文件

1
2
3
4
5
6
7
8
9
10
11
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>superman</title>
    <link rel="shortcut icon" href="http://www.atguigu.com/images/logo.jpg" type="image/x-icon" />
</head>
<body>
    <h1>欢迎来到 superman 的个人网站</h1>
</body>
</html>
index.html

index.html

Web静态服务器-3-使用类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
from socket import socket,AF_INET,SOL_SOCKET,SOCK_STREAM,SO_REUSEADDR
from multiprocessing import Process
import re

class HttpServer(object):
    HTTP_ROOT_DIR = "./html"

    def __init__(self):
        self.http_socket = socket(AF_INET,SOCK_STREAM)
        self.http_socket.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
        self.http_socket.bind(("",9999))
        self.http_socket.listen(128)

    def handle_ok(self,request,new_socket):
        response_statr = "HTTP1.1 200 OK\r\n"
        response_header = "Content-Type: text/html; charset=utf-8\r\n"
        response_space = "\r\n"
        response_body = request
        response = response_statr + response_header + response_space + response_body
        new_socket.send(response.encode("utf-8"))

    def errors_404(self,new_socket):
        response_statr = "HTTP1.1 404 NOT\r\n"
        response_header = "Content-Type: text/html; charset=utf-8\r\n"
        response_space = "\r\n"
        response_body = "404"
        response = response_statr + response_header + response_space + response_body
        new_socket.send(response.encode("utf-8"))

    def http_recv(self,new_socket):
        recv_data = new_socket.recv(1024)
        request_lins = recv_data.splitlines()
        request_data = re.match(r"\w+ +(/[^ ]*)",request_lins[0].decode("utf-8"))
        file_name = request_data.group(1)
                #读取index.html内容
        if "/index.html" == file_name:
            f = open(HttpServer.HTTP_ROOT_DIR + file_name,"r")
            request = f.read()
            f.close()

        if "/" == file_name:
            f = open(HttpServer.HTTP_ROOT_DIR + "/index.html", "r")
            request = f.read()
            f.close()

        try:#当没有request没有被赋值后,执行404
            self.handle_ok(request,new_socket)
        except:
            self.errors_404(new_socket)

    def main(self):
        try:
            while True:
                new_socket,new_address = self.http_socket.accept()
                print("新用户进来了",new_address)
                Process(target=self.http_recv,args=(new_socket,)).start()
                new_socket.close()
        except:
            self.http_socket.close()

if __name__ == '__main__':
    HttpServer().main()

动态Web服务器–运行python脚本程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
from socket import socket,AF_INET,SOL_SOCKET,SOCK_STREAM,SO_REUSEADDR#套接字关键字
from multiprocessing import Process#导入进程模块
import re#正则模块
import sys#系统相关的信息模块 import sys

class HttpServer(object):
    HTTP_ROOT_DIR = "./html"#常量
    HTTP_WSRI_DIR = "./wsgi"#常量
   
    #初始化套接字
    def __init__(self):
        self.http_socket = socket(AF_INET,SOCK_STREAM)
        self.http_socket.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
        self.http_socket.bind(("",9999))
        self.http_socket.listen(128)

    #正确的发送函数
    def handle_ok(self,request,new_socket):
        response_statr = "HTTP1.1 200 OK\r\n"
        response_header = "Content-Type: text/html; charset=utf-8\r\n"
        response_space = "\r\n"
        response_body = request
        response = response_statr + response_header + response_space + response_body
        new_socket.send(response.encode("utf-8"))

    #错误的发送函数
    def errors_404(self,new_socket):
        response_statr = "HTTP1.1 404 NOT\r\n"
        response_header = "Content-Type: text/html; charset=utf-8\r\n"
        response_space = "\r\n"
        response_body = "404"
        response = response_statr + response_header + response_space + response_body
        new_socket.send(response.encode("utf-8"))
   
    #判断是文件的函数
    def http_recv(self,new_socket):
        recv_data = new_socket.recv(1024)
        request_lins = recv_data.splitlines()
        request_data = re.match(r"\w+ +(/[^ ]*)",request_lins[0].decode("utf-8"))
        file_name = request_data.group(1)
        print(file_name)
       
        #判断是否是/index.html 或者是 py结尾文件
        if "/index.html" == file_name:
            f = open(HttpServer.HTTP_ROOT_DIR + file_name,"r")
            request = f.read()
            f.close()
        elif file_name.endswith(".py"):
            module = file_name[1:-3]
            print(module)
            m = __import__(module)
            request = m.get_ctime()
       
        #判断是否是首页
        if "/" == file_name:
            f = open(HttpServer.HTTP_ROOT_DIR + "/index.html", "r")
            request = f.read()
            f.close()
           
        # 当没有request没有被赋值后,执行404
        try:
            self.handle_ok(request,new_socket)
        except:
            self.errors_404(new_socket)
   
    #开始执行函数
    def main(self):
        sys.path.insert(0,HttpServer.HTTP_WSRI_DIR)
        print(sys.path)
        try:
            while True:
                new_socket,new_address = self.http_socket.accept()
                print("新用户进来了",new_address)
                Process(target=self.http_recv,args=(new_socket,)).start()
                new_socket.close()
        except:
            self.http_socket.close()

if __name__ == '__main__':
    HttpServer().main()

执行的外部py文件代码

1
2
3
4
import time

def get_ctime():
    return time.ctime()
py文件

执行的py文件

WSGI协议–运行python脚本程序

WSGI允许开发者将选择web框架和web服务器分开。可以混合匹配web服务器和web框架,选择一个适合的配对。比如,可以在Gunicorn 或者 Nginx/uWSGI 或者 Waitress上运行 Django, Flask, 或 Pyramid。真正的混合匹配,得益于WSGI同时支持服务器和架构:

wsgi

wsgi

wsgi协议代码,注意这只是一种协议

1
2
3
def application(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    return 'Hello World!'

简单的说:wsgi协议就是一种设计模式,你完全可以不用它去写web服务器,但是没人会这么干。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
from socket import socket,AF_INET,SOL_SOCKET,SOCK_STREAM,SO_REUSEADDR#套接字关键字
from multiprocessing import Process#导入进程模块
import re#正则模块
import sys#系统相关的信息模块 import sys

class HttpServer(object):
    HTTP_ROOT_DIR = "./html"#常量
    HTTP_WSRI_DIR = "./wsgi"#常量

    #初始化套接字
    def __init__(self):
        self.http_socket = socket(AF_INET,SOCK_STREAM)
        self.http_socket.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
        self.http_socket.bind(("",9999))
        self.http_socket.listen(128)

    # #正确的发送函数
    # def handle_ok(self,request,new_socket):
    #   response_statr = "HTTP1.1 200 OK\r\n"
    #   response_header = "Content-Type: text/html; charset=utf-8\r\n"
    #   response_space = "\r\n"
    #   response_body = request
    #   response = response_statr + response_header + response_space + response_body
    #   new_socket.send(response.encode("utf-8"))

    # #错误的发送函数
    # def errors_404(self,new_socket):
    #   response_statr = "HTTP1.1 404 NOT\r\n"
    #   response_header = "Content-Type: text/html; charset=utf-8\r\n"
    #   response_space = "\r\n"
    #   response_body = "404"
    #   response = response_statr + response_header + response_space + response_body
    #   new_socket.send(response.encode("utf-8"))

    #根据运行python程序的情况,组织响应给浏览器的头对应信息
    def start_response(self,startus,headers):
        self.response_statr = "HTTP1.1" + startus + "\r\n"#定义实例对象属性
        response_headers = ""#先要给声明,不然下面报错
        for header in headers:
            print(header)#('Content-Type', 'text/html;charset=utf-8')这里是元组直接就赋值了
            response_headers += "%s: %s" %header + "\r\n"#赋值响应头

        self.response_headers = response_headers#定义实例对象属性

    #判断是文件的函数
    def http_recv(self,new_socket):
        recv_data = new_socket.recv(1024)
        request_lins = recv_data.splitlines()
        request_data = re.match(r"\w+ +(/[^ ]*)",request_lins[0].decode("utf-8"))
        file_name = request_data.group(1)
        print(file_name)

        #判断是否是/index.html 或者是 py结尾文件
        if "/index.html" == file_name:
            f = open(HttpServer.HTTP_ROOT_DIR + file_name,"r")
            request = f.read()
            f.close()

        elif file_name.endswith(".py"):
            module = file_name[1:-3]
            print(module)
            m = __import__(module)
            # request = m.get_ctime()

            evn = {}#wsgi协议定义一个参数是字典,第二个是函数
            request_bady = m.application(evn,self.start_response)#调用变量module模块中的application函数
            response = self.response_statr + self.response_headers + "\r\n" + request_bady#组装响应内容
            new_socket.send(response.encode("utf-8"))#发送的内容

        #判断是否是首页
        if "/" == file_name:
            f = open(HttpServer.HTTP_ROOT_DIR + "/index.html", "r")
            request = f.read()
            f.close()

        # 当没有request没有被赋值后,执行404
        # try:
        #   self.handle_ok(request,new_socket)
        # except:
        #   self.errors_404(new_socket)

    #开始执行函数
    def main(self):
        sys.path.insert(0,HttpServer.HTTP_WSRI_DIR)
        print(sys.path)
        try:
            while True:
                new_socket,new_address = self.http_socket.accept()
                print("新用户进来了",new_address)
                Process(target=self.http_recv,args=(new_socket,)).start()
                new_socket.close()
        except:
            self.http_socket.close()

if __name__ == '__main__':
    HttpServer().main()

执行的外部py文件代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import time

def get_ctime():
    return time.ctime()

#参数1web服务器的请求路径和方法
#参数2web服务器的函数引用,作用组装响应行和响应头
#appliction 在框架里面
#appliction 有返回值,响应体的内容

def application(env,start_response):
    startus = "200 OK"
    headers = [("Content-Type","text/html;charset=utf-8")]#有可能有多个信息所以放在列表中在放到元组中
    start_response(startus,headers)#调用服务器start_response函数
    return "这是wsgi协议返回的内容"

添加一个404.py文件

执行代码局部修改

1
2
3
4
5
6
7
8
9
10
11
12
13
elif file_name.endswith(".py"):
    module = file_name[1:-3]
    print(module)
    try:
        m = __import__(module)
        # request = m.get_ctime()
    except ImportError:
        m = __import__("404")

    evn = {}#wsgi协议定义一个参数是字典,第二个是函数
    request_bady = m.application(evn,self.start_response)#调用变量module模块中的application函数
    response = self.response_statr + self.response_headers + "\r\n" + request_bady#组装响应内容
    new_socket.send(response.encode("utf-8"))#发送的内容
1
2
3
4
5
6
7
8
9
10
#参数1web服务器的请求路径和方法
#参数2web服务器的函数引用,作用组装响应行和响应头
#appliction 在框架里面
#appliction 有返回值,响应体的内容

def application(env,start_response):
    startus = "404 NOT"
    headers = [("Content-Type","text/html;charset=utf-8")]#有可能有多个信息所以放在列表中在放到元组中
    start_response(startus,headers)#调用服务器start_response函数
    return "404"

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!

2条评论
  • 创业网

    2018 年 1 月 13 日 15:31

    我有强迫症,看到好文就想顶!

  • 套图网

    2018 年 1 月 7 日 14:43

    毫无疑问,这个是要支持的!

发表评论

电子邮件地址不会被公开。 必填项已用*标注