python之socket搭建静态页面服务器


写在前面

最近在学习Django,对于底层的信息交换产生了些许兴趣,而且前段时间看一个同事使用c++写socket,今天我查了点资料,自己也写写试试

用到的包

#socket相关
from socket import *
#线程相关
from threading import Thread
#系统模块
import os
#正则匹配,从请求中匹配html文件路径
import re

筛查请求

def get_request_name_from_http(http:str) -> str:
    #从请求中匹配静态文件地址
    r = re.search(r"GET /(.+?) ",http)
    filename = ""
    if r != None:
        filename = r.group(1)
    #返回相对路径的文件地址
    return filename

服务器数据

#构建Response header和Response数据,并从服务器发送给用户
def writeHtml(client,filename):
    rspHead = None
    rspBody = None
    if not os.path.exists(filename):
        rspHead = "HTTP/1.1 404 error\r\nServer: foreverServer\r\n\r\n"
        rspBody = "file not found"
    else:
        rspHead = "HTTP/1.1 200 OK\r\nServer: foreverServer\r\n\r\n"
        html = open(filename,'r',encoding="UTF-8")
        rspBody = html.read()
    client.send((rspHead + rspBody).encode('UTF-8'))

线程调用函数

def deal_socket(client):
    try:
        #1024代表请求的最大字节数
        data = client.recv(1024)
        if len(data) > 0:
            #获取目标html文件地址
            fileName = get_request_name_from_http(data.decode("utf-8"))
            #获取Response信息后发送到客户端
            writeHtml(client, fileName)
    finally:
        #关闭连接
        client.close()

主函数

def main():
    #初始化socket服务
    server = socket(AF_INET,SOCK_STREAM)
    server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
    #ip和端口,默认为localhost(127.0.0.1)
    address = ('',8000)
    #与端口绑定
    server.bind(address)
    #监听,括号内为限制连接数量
    server.listen(10)
    try:
        while True:
            #初始化连接
            client,client_address = server.accept()
            #输出服务器ip和端口
            print(client_address)
            #初始化一个线程
            p = Thread(target=deal_socket,args=(client,))
            #启动线程
            p.start()
    except Exception as e:
        print(e)
    finally:
        #关闭服务器
        server.close()

完整代码

# -*- coding: utf-8 -*-
"""
Created on Thu Feb 18 18:40:58 2021

@author: Administrator
"""

from socket import *
from threading import Thread
import os
import re

def get_request_name_from_http(http:str) -> str:
    r = re.search(r"GET /(.+?) ",http)
    filename = ""
    if r != None:
        filename = r.group(1)
    return filename

def writeHtml(client,filename):
    rspHead = None
    rspBody = None
    if not os.path.exists(filename):
        rspHead = "HTTP/1.1 404 error\r\nServer: foreverServer\r\n\r\n"
        rspBody = "file not found"
    else:
        rspHead = "HTTP/1.1 200 OK\r\nServer: foreverServer\r\n\r\n"
        html = open(filename,'r',encoding="UTF-8")
        rspBody = html.read()
    client.send((rspHead + rspBody).encode('UTF-8'))

def deal_socket(client):
    try:
        data = client.recv(1024)
        if len(data) > 0:
            fileName = get_request_name_from_http(data.decode("utf-8"))
            writeHtml(client, fileName)
    finally:
        client.close()

def main():
    server = socket(AF_INET,SOCK_STREAM)
    server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
    address = ('',8000)
    server.bind(address)
    server.listen(10)
    try:
        while True:
            client,client_address = server.accept()
            print(client_address)
            p = Thread(target=deal_socket,args=(client,))
            p.start()
    except Exception as e:
        print(e)
    finally:
        server.close()

if __name__ == '__main__':
    main()

html和访问

在py文件同目录下新建index.html:

<!DOCTYPE html>
<head>
    <title>index</title>
</head>
<body>
<h1>Hello World!</h1>
</body>

运行py文件,在浏览器访问127.0.0.1:8000/index.html即可

写在后面

代码是从简书抄来的,下午的时候用的是另一个代码,使用的是Process而非Thread,但是在这里发现了一个小问题,代码封装成类后无法正常访问,明天有空再Debug。