python:模拟HTML笔记

代码1:基础实现可以用网页向程序请求页面

import socket
import os
import re

web_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
web_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
web_socket.bind(('', 10241))

web_socket.listen(124)

data = web_socket.accept()

new_socket = data[0]

info = new_socket.recv(1024)

info_str = info.decode()
print(info_str)
info_str = info_str.split('\r\n')
print(info_str[0])
path = re.match(r'\S+\s+/(\S+)\s+\S+', info_str[0])
file_path = path.group(1)
if os.path.exists(file_path):
    # 响应行:协议/版本号 状态码\r\n
    respond_line = 'HTTP/1.1 200 OK \r\n'
    # 响应头:服务器:型号\r\n
    respond_hande = 'Server: PYS1.0\r\n'
    # 响应体: 内容,网页的内容全部读出来
    path = info
    f = open('index.html', 'rb')
    content = f.read()
    f.close()
    respond_body = content

    respond_data = (respond_line + respond_hande + '\r\n').encode() + respond_body
    new_socket.send(respond_data)
new_socket.close()
web_socket.close()

1.添加下面语句,使得程序结束以后可以将端口释放:

web_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

2.使用data = web_socket.accept()可以得到一个元组,包含两组数据,一组为:新的套接字;另一组为对端ip和port:

    (<socket.socket fd=4, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 10241), raddr=('127.0.0.1', 57504)>, ('127.0.0.1', 57504))

3.下面的语句得到的是一串二进制数据,需要进行(.decode())解码才能继续操作:

    info = new_socket.recv(1024)

4.上一句经过解码后得到的以下数据(请求行,头,空行(看不出来\r\t),体):

GET /index.html HTTP/1.1                                    请求行:方法 /路径 版本
Host: localhost:10241                                       地址,端口
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:59.0) Gecko/20100101 Firefox/59.0    用户代理    
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8             可以接受的文本类型
Accept-Language: en-US,en;q=0.5                                 可以接受的语言
Accept-Encoding: gzip, deflate                                  可以接受的压缩格式
Connection: keep-alive                                      长链接
Upgrade-Insecure-Requests: 1

代码2:使用协程完成代码1

import socket
import re
import os
import gevent
from gevent import monkey
monkey.patch_all()      # 把默认的阻塞模式变为非阻塞的模式 recv accept time.sleep


# 用来进行与客户端交互
def client(new_socket):
    info = new_socket.recv(4096)
    de_info = info.decode()
    hander = de_info.split('\r\n')
    web_name = re.match(r'\S+\s+/(\S+)\s+\S+', hander[0])
    print(web_name.group(1))
    path = web_name.group(1)
    print(path)
    try:
        f = open('static/' + path, 'rb')
        content = f.read()
        f.close()
        respond_body = content
        respond_hander = 'Server PYW9.9 \r\n'
        respond_line = 'HTTP/1.1 200 OK \r\n'
        respond_data = (respond_line + respond_hander + '\r\n').encode() + respond_body

    except Exception as e:
        respond_body = 'Error'
        respond_line = 'HTTP/1.1 404 Error \r\n'
        respond_hander = 'Server PYW9.9 \r\n'
        respond_data = (respond_line + respond_hander + '\r\n' + respond_body).encode()

    finally:
        new_socket.send(respond_data)
        new_socket.close()


def main():
    web_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    web_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    web_socket.bind(('', 7991))
    web_socket.listen(124)
    while True:
        new_socket, ip_port = web_socket.accept()
        print('接收到来自%s的链接请求' % str(ip_port))

        gevent.spawn(client, new_socket)


if __name__ == '__main__':
    main()

1.在模仿网页发送响应行、头时应该严格按照格式来,对比下面四句:
respond_line = ‘HTTP/1.1 200 OK \r\n’
respond_line = ‘HTTP/ 1.1 200 OK \r\n’
respond_line = ‘HTTP /1.1 200 OK \r\n’
respond_line = ‘HTTP / 1.1 200 OK \r\n’
只有第一句可以完美执行,第2 3 4句在chrome上可以正常浏览,在Firefox上会直接看到网页源码,看不到正常网页。

代码3:对代码2进行封装,并可以在命令行向程序输入参数

import socket
import sys
import re
import gevent
from gevent import monkey
monkey.patch_all()      # 把默认的阻塞模式变为非阻塞的模式 recv accept time.sleep


class HTTP_Server():
    '''这是一个HTTP服务器端'''
    def __init__(self, port):
        web_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        web_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        web_socket.bind(('', port))
        web_socket.listen(124)
        self.socket = web_socket

    def star(self):
        while True:
            new_socket, ip_port = self.socket.accept()
            print('接收到来自%s的链接请求' % str(ip_port))
            gevent.spawn(self.client, new_socket)

    # 用来进行与客户端交互
    def client(self, new_socket):
        info = new_socket.recv(4096)
        de_info = info.decode()
        hander = de_info.split('\r\n')
        web_name = re.match(r'\S+\s+/(\S+)\s+\S+', hander[0])
        print(web_name.group(1))
        path = web_name.group(1)
        print(path)
        try:
            f = open('static/' + path, 'rb')
            content = f.read()
            f.close()
            respond_body = content
            respond_hander = 'Server PYW9.9 \r\n'
            respond_line = 'HTTP/1.1 200 OK \r\n'
            respond_data = (respond_line + respond_hander + '\r\n').encode() + respond_body

        except Exception as e:
            respond_body = 'Error'
            respond_line = 'HTTP/1.1 404 Error \r\n'
            respond_hander = 'Server PYW9.9 \r\n'
            respond_data = (respond_line + respond_hander + '\r\n' + respond_body).encode()

        finally:
            new_socket.send(respond_data)
            new_socket.close()


def main():
    if len(sys.argv) != 2:
        print("正确打开方式: python3 web.py 8888")
        return
    if not sys.argv[1].isdigit():
        print("正确打开方式: python3 web.py 8888")

    port = int(sys.argv[1])
    Http = HTTP_Server(port)
    print(HTTP_Server.__doc__)
    Http.star()


if __name__ == '__main__':
    main()

猜你喜欢

转载自blog.csdn.net/qq_28311921/article/details/79993023