震精:Python 200行代码实现简单的WebServer,还支持图片加载(WSGI,Socket ,TCP,thread)

1、代码程序结构如下:

static——静态文件目录

templates——html模板文件目录

application.py——TCP连接监听和工作线程处理收发数据

request.py——解析http请求

response.py——封装发送数据模块

runserver.py——服务器启动main模块

2、具体代码实现

application.py

import socket
import threading
from response import HttpResponse
from request  import HttpRequest

# WSGI服务器
class WSGIServer():

    def __init__(self, host='localhost', port=8080, connectSize=100):
        '''
        :param port: 服务器的端口号
        :param connectSize: 默认的并发数量
        '''
        self.__host = host
        self.__port = port
        self.__connectSize = connectSize
        pass

    def startServer(self):
        '''
        服务启动主程序
        :return:
        '''
        server = None
        try:
            server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            server.bind((self.__host, self.__port))
            server.listen(self.__connectSize)
            while True:
                print("======服务器启动成功:http://" + self.__host + ":" + str(self.__port))
                clientConn, clientAddr = server.accept()  # 等待客户端请求
                # 启动独立的线程,处理每一次用户请求
                wt = WorkThread(clientConn, clientAddr)
                wt.start()
                pass
        except socket.gaierror as g:
            print(g)
        finally:
            if server:
                server.close()
        pass

    pass

class WorkThread(threading.Thread):
    def __init__(self, connection, addr, bufferSize=8096):
        threading.Thread.__init__(self)
        self.__connection = connection
        self.__addr = addr
        self.__bufferSize = bufferSize
        pass

    def run(self):
        receiveMsg = self.__connection.recv(self.__bufferSize)
        receiveMsg = receiveMsg.decode("utf-8")
        print(receiveMsg)
        request = HttpRequest()
        params = request.parseRequest(receiveMsg)
        responseText = ""
        response = HttpResponse()
        if params['Accept'].find('text/html') >=0:
            url = 'templates/index.html'
            if params['url'] == "/":
                url = 'templates/index.html'
            else:
                url = 'templates' + params['url']
                if params['url'] == '/main.html':
                    if params.get('dataparams').get('userName') != 'zhangsan':
                        url = 'templates/index.html'
                        responseText = response.responseHeader('text/html', 200) + "\n" + response.responseBodyText(url)
                        pass
                    pass
            responseText = response.responseHeader('text/html', 200) + "\n" + response.responseBodyText(url)
            self.__connection.send(responseText.encode("utf-8"))
            pass
        elif params['Accept'].find('image/') >= 0:
            url = params['url']
            self.__connection.send(response.responseHeader('image/', 200).encode("utf-8"))
            self.__connection.send("\n".encode("utf-8"))
            self.__connection.send(response.responseBodyBinary(url[1:]))
            pass
            print(responseText)

        self.__connection.close()

        pass
    pass

request.py

class HttpRequest():

    def parseRequest(self, requestText):
        params = {}
        lineArray = requestText.split('\r\n')
        row = 1
        isBody = False
        bodyText = ""
        for line in lineArray:
            if row == 1 :
                array = line.split(' ')
                params['method'] = array[0]
                params['url'] = array[1]
                params['httptype'] = array[2]
                row += 1
            elif line.strip() == "":
                isBody = True
            elif not isBody:
                array = line.split(':')
                params[array[0]] = line[len(array[0])+2:]
                pass
            elif isBody:
                bodyText += line
            pass

        params['body'] = bodyText
        dataParams = {}
        bodyText = bodyText.strip()
        if params.get('Content-Type') == 'application/x-www-form-urlencoded' and   params['method'] == 'POST':
            array = bodyText.split('&')
            for data in array:
                keyvalue = data.split("=")
                dataParams[keyvalue[0]] = keyvalue[1]
                pass
            pass
        params['dataparams'] = dataParams
        return params
        pass
    pass

response.py

class HttpResponse():
    def responseHeader(self, contentType, ressponseCode):
        header = "http/1.1 200 OK\r\n"
        if contentType == 'text/html':
                header += "Content-Type: text/html\r\n" + \
                 "X-Ua-Compatible: IE=Edge,chrome=1\r\n"
        elif contentType == "image/":
            header += "Content-Type: image/png\r\n" + \
                      "X-Ua-Compatible: IE=Edge,chrome=1\r\n"
        return header
        pass

    def responseBodyText(self, url):
        body = ""
        with open(url, 'r') as fp:
            body = fp.read()
        return body
        pass

    def responseBodyBinary(self, url):
        body = b""
        with open(url, 'rb') as fp:
            body = fp.read()
        return body
    pass

runserver.py

from application import WSGIServer

if __name__ == '__main__':
    # 创建服务器对象
    wsgiServer = WSGIServer()
    wsgiServer.startServer()
    pass

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
   Hello, my WSGI server!
 <form method="post" action="main.html">
     <input type="text" name="userName">
     <input type="password" name="userPwd">
     <input type="submit"  />
 </form>
</body>
</html>

main.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<img src="static/photo1.png" />
System main page!
</body>
</html>

3、运行效果

发布了34 篇原创文章 · 获赞 54 · 访问量 5001

猜你喜欢

转载自blog.csdn.net/nosprings/article/details/102609296