精华内容
下载资源
问答
  • python实现Web服务器

    2020-01-07 23:11:20
    #模拟浏览器请求web服务器 import socket tcpSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #创建套接字 tcpSocket.connect(("121.36.32.38",80)) requestLine = "GET / HTTP/1.1\r\n" ...

    python深入浅出进阶教程

    web request

    #模拟浏览器请求web服务器
    import socket
    
    tcpSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #创建套接字
    tcpSocket.connect(("121.36.32.38",80))
    requestLine = "GET / HTTP/1.1\r\n"
    requestHeader = "host:www.yaojun.com\r\n"
    requestBlank = "\r\n"
    requestData = requestLine + requestHeader + requestBlank
    tcpSocket.send(requestData.encode()) #已经建立了连接 直接发送
    receiveData = tcpSocket.recv(4096)
    receiveText = receiveData.decode()
    loc = receiveText.find("\r\n\r\n")
    html = receiveText[loc+4:]
    with open("index.html","w+") as f:
        f.write(html)
    tcpSocket.close()
    

    web response

    返回浏览器固定数据

    import socket
    def requestHandler(newsocket,ipPort):
        receiveData = newsocket.recv(1024)
        if not receiveData:
            print("%s客户端已经断开!"%str(ipPort))
            newsocket.close()
            return
        responseLine="HTTP/1.1 200 OK\r\n"
        responseHeader ="Server:Python20WS/2.1\r\n"
        responseBlank ="\r\n"
        responseBody="hello world!"
        responseData = responseLine+responseHeader+responseBlank+responseBody
        newsocket.send(responseData.encode())
        newsocket.close()
        pass
    def main():
        tcpSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #创建套接字
        tcpSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
        tcpSocket.bind(("",8080)) #元组
        tcpSocket.listen(128) #监听上限 在windows 128有效 在linux无效
        while True:
            newSocket,ipPort = tcpSocket.accept() #阻塞等待客户端连接 ipPort是个元组只有两个元素
            print(ipPort[0]) #IP
            print(ipPort[1]) #port
            requestHandler(newSocket,ipPort)
    
    
    if __name__ == '__main__':
        main()
    

    Web Server

    从浏览器打开返回固定页面

    import socket
    def requestHandler(newsocket,ipPort):
        receiveData = newsocket.recv(1024)
        if not receiveData:
            print("%s客户端已经断开!"%str(ipPort))
            newsocket.close()
            return
        responseLine="HTTP/1.1 200 OK\r\n"
        responseHeader ="Server:Python20WS/2.1\r\n"
        responseBlank ="\r\n"
        #从文件中读入固定页面
        with open("index.html", "rb") as f:
            responseBody = f.read() #读入的是二进制文件
        responseData = (responseLine+responseHeader+responseBlank).encode()+responseBody
        newsocket.send(responseData)
        newsocket.close()
        pass
    def main():
        tcpSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #创建套接字
        tcpSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
        tcpSocket.bind(("",8080)) #元组
        tcpSocket.listen(128) #监听上限 在windows 128有效 在linux无效
        while True:
            newSocket,ipPort = tcpSocket.accept() #阻塞等待客户端连接 ipPort是个元组只有两个元素
            print(ipPort[0]) #IP
            print(ipPort[1]) #port
            requestHandler(newSocket,ipPort)
    
    
    if __name__ == '__main__':
        main()
    

    Web Server

    返回指定页面localhost:8080/index.html
    注意需要在当前目录下增加一个favicon.ico文件

    import socket
    def requestHandler(newsocket,ipPort):
        receiveData = newsocket.recv(1024)
        if not receiveData:
            print("%s客户端已经断开!"%str(ipPort))
            newsocket.close()
            return
        #拆分请求
        receiveText = receiveData.decode()
        loc = receiveText.find("\r\n")
        requestLine= receiveText[:loc].split()
        filePath = requestLine[1]
        if filePath == "/":
            filePath = "index.html"
        else:
            filePath = filePath[1:]
        responseLine="HTTP/1.1 200 OK\r\n"
        responseHeader ="Server:Python20WS/2.1\r\n"
        responseBlank ="\r\n"
        #从文件中读入固定页面 如果页面不存在使用异常捕获
        try:
            with open(filePath, "rb") as f:
                responseBody = f.read() #读入的是二进制文件
        except Exception as e:
            responseLine = "HTTP/1.1 404 Not Found\r\n"
            responseBody = "Error!%s"%str(e)
            responseBody = responseBody.encode() #编码为二进制
        responseData = (responseLine+responseHeader+responseBlank).encode() + responseBody
        newsocket.send(responseData)
        newsocket.close()
    
    def main():
        tcpSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #创建套接字
        tcpSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
        tcpSocket.bind(("",8080)) #元组
        tcpSocket.listen(128) #监听上限 在windows 128有效 在linux无效
        while True:
            newSocket,ipPort = tcpSocket.accept() #阻塞等待客户端连接 ipPort是个元组只有两个元素
            print(ipPort[0]) #IP
            print(ipPort[1]) #port
            requestHandler(newSocket,ipPort)
    
    
    if __name__ == '__main__':
        main()
    

    面向对象封装

    import socket
    
    class WebServer(object):
        def __init__(self):
            tcpSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # 创建套接字
            tcpSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
            tcpSocket.bind(("", 8080))  # 元组
            tcpSocket.listen(128)  # 监听上限 在windows 128有效 在linux无效
            self.tcpSocket = tcpSocket
    
        def start(self):
            while True:
                newSocket, ipPort = self.tcpSocket.accept()  # 阻塞等待客户端连接 ipPort是个元组只有两个元素
                print(ipPort[0])  # IP
                print(ipPort[1])  # port
                self.requestHandler(newSocket, ipPort)
    
        def requestHandler(self, newsocket,ipPort):
            receiveData = newsocket.recv(1024)
            if not receiveData:
                print("%s客户端已经断开!"%str(ipPort))
                newsocket.close()
                return
            #拆分请求
            receiveText = receiveData.decode()
            loc = receiveText.find("\r\n")
            requestLine= receiveText[:loc].split()
            filePath = requestLine[1]
            if filePath == "/":
                filePath = "/index.html"
    
            responseLine="HTTP/1.1 200 OK\r\n"
            responseHeader ="Server:Python20WS/2.1\r\n"
            responseBlank ="\r\n"
            #从文件中读入固定页面 如果页面不存在使用异常捕获
            try:
                with open("staticPage"+filePath, "rb") as f:
                    responseBody = f.read() #读入的是二进制文件
            except Exception as e:
                responseLine = "HTTP/1.1 404 Not Found\r\n"
                responseBody = "Error!%s"%str(e)
                responseBody = responseBody.encode() #编码为二进制
            responseData = (responseLine+responseHeader+responseBlank).encode() + responseBody
            newsocket.send(responseData)
            newsocket.close()
    
    def main():
        ws = WebServer()
        ws.start()
    
    if __name__ == '__main__':
        main()
    

    服务端基础框架构建

    分模块
    子文件:staticPage application

    import socket
    #导入模块
    from application import app
    class WebServer(object):
        def __init__(self):
            tcpSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # 创建套接字
            tcpSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
            tcpSocket.bind(("", 8080))  # 元组
            tcpSocket.listen(128)  # 监听上限 在windows 128有效 在linux无效
            self.tcpSocket = tcpSocket
    
        def start(self):
            while True:
                newSocket, ipPort = self.tcpSocket.accept()  # 阻塞等待客户端连接 ipPort是个元组只有两个元素
                self.requestHandler(newSocket, ipPort)
    
        def requestHandler(self, newsocket,ipPort):
            receiveData = newsocket.recv(1024)
            if not receiveData:
                print("%s客户端已经断开!"%str(ipPort))
                newsocket.close()
                return
            #拆分请求
            responseData = app.app("staticPage", receiveData, ipPort)
            newsocket.send(responseData)
            newsocket.close()
    
    def main():
        ws = WebServer()
        ws.start()
    
    if __name__ == '__main__':
        main()
    

    应用模块

    def parseRequest(receiveData, ipPort):
        '''解析请求的报文 返回客户端请求的资源路径'''
        receiveText = receiveData.decode()
        loc = receiveText.find("\r\n")
        requestLine = receiveText[:loc].split(" ")
        filePath = requestLine[1]
        print("%s正在请求:%s" % (str(ipPort), filePath))
        if filePath == "/":
            filePath = "/index.html"
        return filePath
    
    def app(currentDir, receiveData,ipPort):
        filePath = parseRequest(receiveData, ipPort)
        resourcePath = currentDir + filePath
        responseLine = "HTTP/1.1 200 OK\r\n"
        responseHeader = "Server:Python20WS/2.1\r\n"
        responseBlank = "\r\n"
        # 从文件中读入固定页面 如果页面不存在使用异常捕获
        try:
            with open(resourcePath, "rb") as f:
                responseBody = f.read()  # 读入的是二进制文件
        except Exception as e:
            responseLine = "HTTP/1.1 404 Not Found\r\n"
            responseBody = "Error!%s" % str(e)
            responseBody = responseBody.encode()  # 编码为二进制
        responseData = (responseLine + responseHeader + responseBlank).encode() + responseBody
        return responseData
    

    Web Server

    带命令行参数

    import socket
    import sys
    #导入模块
    from application import app
    class WebServer(object):
        def __init__(self,port):
            tcpSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # 创建套接字
            tcpSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
            tcpSocket.bind(("", port))  # 元组
            tcpSocket.listen(128)  # 监听上限 在windows 128有效 在linux无效
            self.tcpSocket = tcpSocket
    
        def start(self):
            while True:
                newSocket, ipPort = self.tcpSocket.accept()  # 阻塞等待客户端连接 ipPort是个元组只有两个元素
                self.requestHandler(newSocket, ipPort)
    
        def requestHandler(self, newsocket,ipPort):
            receiveData = newsocket.recv(1024)
            if not receiveData:
                print("%s客户端已经断开!"%str(ipPort))
                newsocket.close()
                return
            #拆分请求
            responseData = app.app("staticPage", receiveData, ipPort)
            newsocket.send(responseData)
            newsocket.close()
    
    def main():
        paraList=sys.argv
        if len(paraList)==2 and  paraList[1].isdigit():
            print("启动成功!")
        else:
            print("启动失败!参数错误或者端口不是数字")
            return
        port = int(paraList[1])
        ws = WebServer(port)
        ws.start()
    
    if __name__ == '__main__':
        main()
    

    app模块

    from application import utils
    def parseRequest(receiveData, ipPort):
        '''解析请求的报文 返回客户端请求的资源路径'''
        receiveText = receiveData.decode()
        loc = receiveText.find("\r\n")
        requestLine = receiveText[:loc].split(" ")
        filePath = requestLine[1]
        print("%s正在请求:%s" % (str(ipPort), filePath))
        if filePath == "/":
            filePath = "/index.html"
        return filePath
    
    def app(currentDir, receiveData,ipPort):
        filePath = parseRequest(receiveData, ipPort)
        resourcePath = currentDir + filePath
    
        # 从文件中读入固定页面 如果页面不存在使用异常捕获
        try:
            with open(resourcePath, "rb") as f:
                responseBody = f.read()  # 读入的是二进制文件
                responseData = utils.CreateHttpResponse("200 OK", responseBody)
        except Exception as e:
    
            responseBody = "Error!%s" % str(e)
            responseBody = responseBody.encode()  # 编码为二进制
            responseData = utils.CreateHttpResponse("404 Not Found", responseBody)
        return responseData
    

    utils模块

    def CreateHttpResponse(status, responseBody):
        '''返回响应数据'''
        responseLine = "HTTP/1.1 %s\r\n" % status
        responseHeader = "Server:Python20WS/2.1\r\n"
        responseBlank = "\r\n"
        responseData = (responseLine + responseHeader + responseBlank).encode() + responseBody
        return responseData
    
    展开全文
  • python实现web服务器

    2020-06-15 14:42:06
    client.sendall(data) client.close() if __name__ == '__main__': main() web服务器其 from socket import * def handle_client(client_socket): """为一个客户端服务""" # 接收对方发送的数据 recv_data = client_...

    发送单个文件

    浏览器使用http://localhost:8080访问

    import socket
     
    server_html=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
     
    server_html.bind(("127.0.0.1",8080))
     
    server_html.listen(10)
     
    while True:
     
        client,addr=server_html.accept()
        msg=client.recv(1024*12)
        print(client)
        #以字节读取数据的权限去打开html_pro.html文件
        file_html=open("html/capture.html","rb")
        #读取文件内容
        data=file_html.read()
        #下面这句话必须写,关于http协议的内容,以后说
        response_headers = "HTTP/1.1 200 OK\r\n" # 200 表示找到这个资源
        response_headers += "\r\n" # 空一行与body隔开
        client.sendall(bytes(response_headers,"utf-8")) 
        #发送读取的内容
        client.sendall(data)
        client.close()
        
    if __name__ == '__main__':
        main()
    

    web服务器其

    from socket import *
     
    def handle_client(client_socket):
        """为一个客户端服务"""
        # 接收对方发送的数据
        recv_data = client_socket.recv(1024).decode("utf-8") #  1024表示本次接收的最大字节数
        # 打印从客户端发送过来的数据内容
        #print("client_recv:",recv_data)
        request_header_lines = recv_data.splitlines()
        for line in request_header_lines:
            print(line)
         
        # 返回浏览器数据
        # 设置返回的头信息 header
        response_headers = "HTTP/1.1 200 OK\r\n" # 200 表示找到这个资源
        response_headers += "\r\n" # 空一行与body隔开
        # 设置内容body
        response_body = "<h1>fat boss<h1>\r\n" 
        response_body += "<h2>come on<h2>\r\n" 
        response_body += "<h3>binlang!!!<h3>\r\n" 
     
        # 合并返回的response数据
        response = response_headers + response_body
        
        # 返回数据给浏览器
        client_socket.send(response.encode("utf-8"))   #转码utf-8并send数据到浏览器
        client_socket.close()
     
    def main():
       # 创建套接字
       server_socket = socket(AF_INET, SOCK_STREAM)
       # 设置当服务器先close 即服务器端4次挥手之后资源能够立即释放,这样就保证了,下次运行程序时 可以立即绑定7788端口
       server_socket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
       # 设置服务端提供服务的端口号
       server_socket.bind(('', 7788))
       # 使用socket创建的套接字默认的属性是主动的,使用listen将其改为被动,用来监听连接
       server_socket.listen(128) #最多可以监听128个连接
       # 开启while循环处理访问过来的请求 
       while True:
          # 如果有新的客户端来链接服务端,那么就产生一个新的套接字专门为这个客户端服务
          # client_socket用来为这个客户端服务
          # server_socket就可以省下来专门等待其他新的客户端连接while True:
          client_socket, clientAddr = server_socket.accept()
          handle_client(client_socket)
     
    if __name__ == "__main__":
       main()
    
    展开全文
  • 摘要本文主要是介绍用python自带的BaseHTTPRequestHandler,HTTPServer类实现一个简易的web服务器,从而加深对http协议和web服务器实现、运行原理的理解,同时对web服务器与客户端的交互过程进行详细介绍,明白服务器...

    摘要

    本文主要是介绍用python自带的BaseHTTPRequestHandler,HTTPServer类实现一个简易的web服务器,从而加深对http协议和web服务器实现、运行原理的理解,同时对web服务器与客户端的交互过程进行详细介绍,明白服务器是如何处理客户端对其请求后,将服务器资源响应给客户端的,更重要的是通过本项目的实现可以了解python的网络开发基础模块和CGI协议,从而拥有能够深入学习python网络开发体系知识基础。

    1.引言

    对于web应用服务器,相信只要是接触B/S架构开发的都会非常熟悉,动态网页的运行是要在web服务器这样的容器中进行处理,然后将数据返回到客户端进行显示的,对于php,最常见的是Apache,而jsp则是tomcat等轻量级应用服务器的使用是很普遍的,而这些服务器部署起来很容易,但是其实现原理却值得探究。

    正好这段时间学习了python,想着实现一个最简单的web服务器应用,可以对客户端的请求进行响应,从而正常显示资源页面。

    2.系统结构

    对使用的相关技术,相关模块进,实现功能的原理进行介绍,采用框架图,示例图等进行表述,使人可以对系统的框架和原理有个比较好的把握;

    用python实现简易服务器,前提需要知道以下几个点:

    2.1 B/S架构原理

    B代表的是浏览器,S代表的是服务器,B/S交互流程:

    [if !supportLists]1.  [endif]用户在客户端向服务器发送请求,等待服务器响应;

    [if !supportLists]2.  [endif]服务器端接收到请求后,对请求的数据进行处理,并产生响应资源数据;

    [if !supportLists]3.  [endif]服务器将产生的资源数据返回给客户端浏览器

    [if !supportLists]4.  [endif]浏览器接收并进行解析相关资源文件,然后呈现在客户端界面。

    简单原理图如下:

    9d73b049d619

    图1 B/S架构原理

    2.2 http协议工作原理

    http是客户端和服务器端请求和应答的标准,是基于TCP/IP协议之上的应用层协议.

    工作原理:当客户端发起一个http请求时,客户端创建一个到服务器指定端口(http默认端口号80)的TCP连接,服务器在指定端口号监听客户端的请求,一旦接收到请求,服务器回向客户端返回一个状态包含状态码以及返回的内容.

    http状态码:

    [if !supportLists]·        [endif]1xx消息——请求已被服务器接收,继续处理

    [if !supportLists]·        [endif]2xx成功——请求已成功被服务器接收、理解、并接受

    [if !supportLists]·        [endif]3xx重定向——需要后续操作才能完成这一请求

    [if !supportLists]·        [endif]4xx请求错误——请求含有词法错误或者无法被执行

    [if !supportLists]·        [endif]5xx服务器错误——服务器在处理某个正确请求时发生错误

    [if !vml]

    [endif]

    9d73b049d619

    图2 http请求及响应数据

    2.3 URL

    URL,全称是UniformResourceLocator, 中文叫统一资源定位符,是互联网上用来标识某一处资源的地址,就是在浏览器中键入的网址.

    2.4 HTTPServer、BaseHTTPRequestHandler

    HTTPServer

    继承SocketServer.TCPServer,用于获取请求,并将请求分配给应答程序处理

    HttpServer的处理过程如下:

    [if !supportLists]1.[endif]HTTPServer绑定对应的应答类(BaseHTTPRequestHandler ),http_server = HTTPServer(('', int(port)), ServerHTTP);

    [if !supportLists]2.  [endif]监听端口:serve_forever()方法使用select.select()循环监听请求,当接收到请求后调用当监听到请求时,取出请求对象;

    [if !supportLists]3.  [endif] 应答:创建新线程以连接对象为参数实例化应答类:ServerHTTP()应答类根据请求方式调用ServerHTTP.do_XXX处理方法

    BaseHTTPRequestHandler

    继承SocketServer.StreamRequestHandler,对http连接的请求作出应答(response)是一个以TCPServer为基础开发的模块,可以在请求外层添加http协议报文,发送http协议。

    3.实验代码

    3.1首先导入相关模块

    import sys,os, subprocess

    fromhttp.server import BaseHTTPRequestHandler,HTTPServer

    [if !supportLists]3.2[endif]条件处理基类

    classbase_case(object):

    def handle_file(self, handler, full_path):

    try:

    with open(full_path, 'rb') as reader:

    content = reader.read()

    handler.send_content(content)

    except IOError as msg:

    msg = "'{0}' cannot be read: {1}".format(full_path, msg)

    handler.handle_error(msg)

    def index_path(self, handler):

    return os.path.join(handler.full_path, 'index.html')

    def test(self, handler):

    assert False, 'Not implemented.'

    def act(self, handler):

    assert False, 'Not implemented.'

    [if !supportLists]3.3[endif]CGI协议处理实现类

    classcase_cgi_file(base_case):

    def run_cgi(self,handler):

    data =subprocess.check_output(["python3", handler.full_path],shell=False)

    handler.send_content(data)

    def test(self, handler):

    return os.path.isfile(handler.full_path) and \

    handler.full_path.endswith('.py')

    def act(self, handler):

    self.run_cgi(handler)

    [if !supportLists]3.4[endif]文件或目录不存在的情况下服务器处理实现

    classcase_no_file(base_case):

    def test(self,handler):

    return not os.path.exists(handler.full_path)

    def act(self, handler):

    raise ServerException("'{0}' not found".format(handler.path))

    3.5当服务器存在文件时,服务器的处理实现

    classcase_existing_file(base_case):

    def test(self, handler):

    return os.path.isfile(handler.full_path)

    def act(self, handler):

    self.handle_file(handler, handler.full_path)

    3.6客户端直接输入URL,返回index主页面

    class case_directory_index_file(base_case):

    def test(self, handler): #判断目标路径下是否有index.html主页面

    returnos.path.isdir(handler.full_path) and \

    os.path.isfile(self.index_path(handler))

    def act(self, handler): #对index.html的内容进行响应

    self.handle_file(handler,self.index_path(handler))

    3.7默认处理类

    classcase_always_fail(base_case):

    def test(self, handler):

    return True

    def act(self, handler):

    raiseServerException("Unknown object '{0}'".format(handler.path))

    3.8当客户端请求路径合法返回响应的处理,如果不合法,返回错误页面实现RequestHandler类

    class RequestHandler(BaseHTTPRequestHandler):

    Cases = [case_no_file(),

    case_cgi_file(),

    case_existing_file(),

    case_directory_index_file(),

    case_always_fail()]

    #当请求路径不合法时返回的错误页面模板

    Error_Page = """\

    Error accessing {path}

    {msg}

    """

    #重写do_GET函数

    def do_GET(self):

    try:

    #得到完整的请求路径

    self.full_path = os.getcwd() + self.path

    #遍历所有的情况并处理

    for case in self.Cases:

    if case.test(self):

    case.act(self)

    break

    #进行异常处理

    except Exception as msg:

    self.handle_error(msg)

    def handle_error(self, msg):

    content = self.Error_Page.format(path=self.path, msg=msg)

    self.send_content(content.encode("utf-8"), 404)

    # 将数据发送到客户端

    def send_content(self, content, status=200):

    self.send_response(status)

    self.send_header("Content-type", "text/html")

    self.send_header("Content-Length", str(len(content)))

    self.end_headers()

    self.wfile.write(content)

    3.9服务器程序异常类

    class ServerException(Exception):

    pass

    3.10主函数实现

    if __name__ == '__main__':

    serverAddress = ('', 8000)  #设置对应端口

    server = HTTPServer(serverAddress,

    RequestHandler) #HTTPServer绑定对应的应答类

    server.serve_forever()  #serve_forever()方法使用select.select()循环监听请求,收到时取出请求对象,创建新线程进行应答

    3.11最后在项目中建立几个用于测试的HTML页面:

    Index.html

    Register.html

    运行server.py程序,再开启浏览器程序进行访问测试

    4.实验结果

    文件目录结构:

    [if !vml]

    [endif]

    9d73b049d619

    客户端浏览器直接访问请求index主页:

    [if !vml]

    [endif]

    9d73b049d619

    客户端浏览器请求同一目录下存在的register.html页面:

    [if !vml]

    [endif]

    9d73b049d619

    客户端浏览器请求不存在的页面:

    [if !vml]

    [endif]

    9d73b049d619

    5.总结和展望

    通过实现基于python的简易web服务器的实现对于B/S架构的理解也不断加深,而且两者之间的通信是基于http、TCP/IP等传输协议的,python中的BaseHTTPRequestHandler, HTTPServer等等相应模块类都能很好的实现这些功能。

    基于python的简易web服务器基本能实现正确处理客户端浏览器的访问请求,并对其进行响应,但是其不足之处是仅限于web服务器中的静态网页,对于动态网页尚未实现相应功能。

    本文核心代码和实现思路主要参考自《500 lines or less》项目,作者是 Mozilla 的 Greg Wilson

    展开全文
  • 1.请自行了解HTTP协议2.创建Socket服务,监听指定IP和端口Paste_Image.png3....准备服务器运行上下文Paste_Image.png6.处理客户端请求数据Paste_Image.png7.根据用户请求路径读取文件Paste_Image.png8.返回响应结果...

    1.请自行了解HTTP协议

    2.创建Socket服务,监听指定IP和端口

    Paste_Image.png

    3.以阻塞方式等待客户端连接

    Paste_Image.png

    4.读取客户端请求数据并进行解析

    Paste_Image.png

    5.准备服务器运行上下文

    Paste_Image.png

    6.处理客户端请求数据

    Paste_Image.png

    7.根据用户请求路径读取文件

    Paste_Image.png

    8.返回响应结果给客户端

    Paste_Image.png

    9.程序入口

    Paste_Image.png

    10.目录结构

    Paste_Image.png

    11.运行

    python wsgiserver.py app:run

    12.源码:

    a.wsgiserver.py文件

    #encoding:utf-8

    import socket

    import StringIO

    import sys

    import logging

    from datetime import datetime

    logger = logging.getLogger(__name__)

    class WSGIServer(object):

    address_family = socket.AF_INET

    socket_type = socket.SOCK_STREAM

    request_queue_size = 30

    recv_size = 1024

    def __init__(self, server_address):

    self._listen_socket = _listen_socket = socket.socket(self.address_family,

    self.socket_type)

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

    _listen_socket.bind(server_address)

    _listen_socket.listen(self.request_queue_size)

    _host, _port = _listen_socket.getsockname()

    self._server_name = socket.getfqdn(_host)

    self._server_port = _port

    self._headers_set = []

    self._application = None

    self._client = None

    self._request_data = None

    self._request_method = None

    self._path = None

    self._request_version = None

    self._start_response = None

    def set_application(self, application):

    self._application = application

    def server_forever(self):

    _listen_socket = self._listen_socket

    logger.info('listen on %s:%s', self._server_name, self._server_port)

    while 1:

    try:

    self._client, _addr = _listen_socket.accept()

    self._handle_request(_addr)

    except KeyboardInterrupt as e:

    logger.info('interrupt')

    break

    except BaseException as e:

    logger.error(e)

    def _handle_request(self, client_addr):

    self._request_data = _request_data = self._client.recv(self.recv_size)

    self._parse_request_data(_request_data)

    _env = self._get_environment(client_addr)

    _result = self._application(_env, self.start_response)

    self._finish_response(_result)

    def _parse_request_data(self, request_data):

    _request_line = str(request_data.splitlines()[0]).rstrip('\r\n')

    (self._request_method, self._path, self._request_version) = _request_line.split()

    def _get_environment(self, client_addr):

    _env = {}

    _env['wsgi.version'] = (1, 0)

    _env['wsgi.url_scheme'] = 'http'

    _env['wsgi.input'] = StringIO.StringIO(self._request_data)

    _env['wsgi.errors'] = sys.stderr

    _env['wsgi.multithread'] = False

    _env['wsgi.multiprocess'] = False

    _env['wsgi.run_once'] = False

    _env['REQUEST_METHOD'] = self._request_method.upper()

    _env['PATH_INFO'] = self._path

    _env['SERVER_NAME'] = self._server_name

    _env['SERVER_PORT'] = self._server_port

    _env['HTTP_CLIENT_IP'] = client_addr[0]

    logger.info('%s %s %s %s', _env['HTTP_CLIENT_IP'], datetime.now().strftime('%Y-%m-%d %H:%M:%S'), _env['REQUEST_METHOD'], _env['PATH_INFO'])

    return _env

    def start_response(self, status, response_headers, exc_info=None):

    _server_headers = [

    ('Date', 'Sun, 7 Jun 2015 23:07:04 GMT'),

    ('Server', 'WSGIServer 0.1')

    ]

    self._headers_set = [status, response_headers + _server_headers]

    def _finish_response(self, result):

    _status, _response_headers = self._headers_set

    _response = 'HTTP/1.1 {status}\r\n'.format(status=_status)

    for _header in _response_headers:

    _response += '{0}:{1}\r\n'.format(*_header)

    _response += '\r\n'

    for _data in result:

    _response += _data

    self._client.sendall(_response)

    self._client.close()

    def make_server(server_address, application):

    server = WSGIServer(server_address)

    server.set_application(application)

    return server

    if __name__ == '__main__':

    logging.basicConfig(level=logging.DEBUG)

    server_addr= ('0.0.0.0', 43002)

    app_path = sys.argv[1]

    module, application = app_path.split(':')

    module = __import__(module)

    application = getattr(module, application)

    httpd = make_server(server_addr, application)

    httpd.server_forever()

    b.app.py文件

    #encoding:utf-8

    import os

    class PageNotFoundException(BaseException):

    pass

    def render(filename, dirname='html'):

    _path = os.path.join(dirname, filename)

    if os.path.exists(_path):

    with open(_path, 'rb') as handler:

    return handler.read()

    raise PageNotFoundException('file not found:%s' % _path)

    def run(env, start_response):

    _path = env.get('PATH_INFO')

    response = ''

    try:

    _path = 'index.html' if _path == '/' else _path[1:]

    if _path.endswith('.css'):

    start_response('200 OK', [('Content-Type', 'text/css')])

    elif _path.endswith('.js'):

    start_response('200 OK', [('Content-Type', 'text/javascript')])

    elif _path.endswith('.html'):

    start_response('200 OK', [('Content-Type', 'text/html')])

    else:

    start_response('200 OK', [('Content-Type', 'text/plain'), ('Content-Disposition', 'attachment; filename=%s' % os.path.basename(_path))])

    response = render(_path)

    except PageNotFoundException as e:

    response = render('404.html')

    return [response, '\r\n']

    展开全文
  • Python实现web服务器入门学习笔记(3)——多进程、多线程实现并发HTTP服务器中,已经学习了如何通过多进程、多线程实现并发HTTP服务器,但当时是以实现功能为导向,并未使用面向对象的封装,本文记录一下如何对...
  • Python实现web服务器入门学习手动实现HTTP服务器中,已经学习了如何通过Python实现一个简单的HTTP服务器,但是问题在于所实现的服务器仅仅是单进程且单线程的,即服务器一次仅可以为一个客户端服务,服务完成之后才...
  • Python实现web服务器入门学习手动实现HTTP服务器中,已经学习了如何通过Python实现一个简单的HTTP服务器,但是问题在于所实现的服务器仅仅是单进程且单线程的,即服务器一次仅可以为一个客户端服务,服务完成之后才...
  • Python实现web服务器入门学习笔记(3)——多进程、多线程实现并发HTTP服务器中,我们知道可以分别通过多进程、多线程的方式实现并发服务器,那么,是否可以通过单进程单线程的程序实现类似功能呢? 实际上,在...
  • Python探索之SocketServer详解中我们介绍了Python标准库中的SocketServer模块,了解了要实现网络通信服务,就要构建一个服务器类和请求处理类。同时,该模块还为我们创建了不同的服务器类和请求处理类。1.服务器类...
  • import reimport socketdef service_cilent(new_socket):request = new_socket.recv(1024).decode("utf-8")# Python splitlines() 按照行('\r', '\r\n', \n')分隔,返回一个包含各行作为元素的列表,如果参数 ...
  • Python实现web服务器入门学习多进程、多线程实现并发HTTP服务器中,我们知道可以分别通过多进程、多线程的方式实现并发服务器,那么,是否可以通过单进程单线程的程序实现类似功能呢?实际上,在Python多任务学习...
  • 一文带你了解如何利用Python实现一个简单的web服务器
  • python日志分析脚本用python可以实现大日志文件的分析,比如查到sql注入语句,然后看到IP,就可以改下脚本,用IP为特征取出日志,分析入侵过程。python比较shell脚本的优点是速度快,性能好,跑1G日志文件也就几秒钟...
  • 一文带你了解如何使用Python实现并发服务器
  • 使用多线程实现的时候,浏览器在刷新的时候会报错,会显示软件中断了连接,这里需要在显示页面部分中添加报错机制 try: # 先返回head client_socket.send(reply_head.encode('utf-8')) # 再返回body ...
  • 文章目录 1.HTTP定义 2.HTTP初体验 2.1 一次简单的HTTP请求和应答 1.HTTP定义 HTTP(HyperText Transfer Protocol)是一种通讯协议,即浏览器(客户端)和web服务器之间向对方发送请求报文前组织待传输报文和收到...
  • = 2: print("正确打开方式: python3 运行程序.py 端口号") return if not sys.argv[1].isdigit(): print("正确打开方式: python3 运行程序.py 端口号") return port = int(sys.argv[1]) http_server = HTTPServer...
  • python3实现微型的web服务器发布时间:2020-09-01 04:02:16来源:脚本之家阅读:105作者:五力实验目的:用socket模拟一个微型的web服务器,当py脚本run起后,实微型web server架起了,然后用本地浏览器访问...
  • 主要为大家详细介绍了python实现静态web服务器,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • HTTP协议简介HTTP请求1:浏览器首先向服务器发送HTTP请求,请求包括:方法:GET还是POST,GET仅请求资源,POST会附带用户数据;路径:/full/url/path;域名:由Host头指定:Host: www.sina.com以及其他相关的Header...
  • Python实现Web静态服务器 在互联网发展的早期很多网站都是静态网站,也就是说只有一个静态页面,例如下图的中国黄页就是一个静态页面,没有任何互动效果。 下图介绍的是客户端向服务器发起请求的过程,因这篇文章...
  • 做web开发的你,真的熟悉web服务器处理机制吗?分析请求数据下面是一段原始的请求数据:b'GET / ...
  • import reimport socketdef service_cilent(new_socket):request = new_socket.recv(1024).decode("utf-8")# Python splitlines() 按照行('\r', '\r\n', \n')分隔,返回一个包含各行作为元素的列表,如果参数 ...
  • #-*- coding:utf-8 -*-importsys, os, BaseHTTPServer, subprocess#-------------------------------------------------------------------------------classServerException(Exception):'''服务器内部错误'''pass#-...
  • Python实现http动态服务器,有两种方法,一种是基本的实现方式,可扩展性差,但是是实现服务器的基础,第二种实现不修改服务器和架构代码而确保可以在多个架构下运行web服务器。都使用WSGI(Web Server Gateway ...
  • 本篇文章小编给大家分享一下Python Web静态服务器非堵塞模式实现方法,小编觉得挺不错的,现在分享给大家供大家参考,有需要的小伙伴们可以来看看。具体代码如下:单进程非堵塞 模型#coding=utf-8from socket import...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,735
精华内容 1,094
关键字:

python实现web服务器

python 订阅