(2018-04-15.Python從Zero到One)四、web服務(wù)器案例__4.1.6Web動(dòng)態(tài)服務(wù)器-1-基本實(shí)現(xiàn)

上一篇文章為:→4.1.5服務(wù)器動(dòng)態(tài)資源請(qǐng)求

Web動(dòng)態(tài)服務(wù)器-1

#coding=utf-8
import socket
import sys
from multiprocessing import Process
import re

class WSGIServer(object):

    addressFamily = socket.AF_INET
    socketType = socket.SOCK_STREAM
    requestQueueSize = 5

    def __init__(self, serverAddress):
        #創(chuàng)建一個(gè)tcp套接字
        self.listenSocket = socket.socket(self.addressFamily,self.socketType)
        #允許重復(fù)使用上次的套接字綁定的port
        self.listenSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        #綁定
        self.listenSocket.bind(serverAddress)
        #變?yōu)楸粍?dòng),并制定隊(duì)列的長(zhǎng)度
        self.listenSocket.listen(self.requestQueueSize)

        self.servrName = "localhost"
        self.serverPort = serverAddress[1]

    def serveForever(self):
        '循環(huán)運(yùn)行web服務(wù)器,等待客戶端的鏈接并為客戶端服務(wù)'
        while True:
            #等待新客戶端到來(lái)
            self.clientSocket, client_address = self.listenSocket.accept()

            #方法2,多進(jìn)程服務(wù)器,并發(fā)服務(wù)器于多個(gè)客戶端
            newClientProcess = Process(target = self.handleRequest)
            newClientProcess.start()

            #因?yàn)閯?chuàng)建的新進(jìn)程中,會(huì)對(duì)這個(gè)套接字+1,所以需要在主進(jìn)程中減去依次,即調(diào)用一次close
            self.clientSocket.close()

    def setApp(self, application):
        '設(shè)置此WSGI服務(wù)器調(diào)用的應(yīng)用程序入口函數(shù)'
        self.application = application

    def handleRequest(self):
        '用一個(gè)新的進(jìn)程,為一個(gè)客戶端進(jìn)行服務(wù)'
        self.recvData = self.clientSocket.recv(2014)
        requestHeaderLines = self.recvData.splitlines()
        for line in requestHeaderLines:
            print(line)

        httpRequestMethodLine = requestHeaderLines[0]
        getFileName = re.match("[^/]+(/[^ ]*)", httpRequestMethodLine).group(1)
        print("file name is ===>%s"%getFileName) #for test

        if getFileName[-3:] != ".py":

            if getFileName == '/':
                getFileName = documentRoot + "/index.html"
            else:
                getFileName = documentRoot + getFileName

            print("file name is ===2>%s"%getFileName) #for test

            try:
                f = open(getFileName)
            except IOError:
                responseHeaderLines = "HTTP/1.1 404 not found\r\n"
                responseHeaderLines += "\r\n"
                responseBody = "====sorry ,file not found===="
            else:
                responseHeaderLines = "HTTP/1.1 200 OK\r\n"
                responseHeaderLines += "\r\n"
                responseBody = f.read()
                f.close()
            finally:
                response = responseHeaderLines + responseBody
                self.clientSocket.send(response)
                self.clientSocket.close()
        else:

            #根據(jù)接收到的請(qǐng)求頭構(gòu)造環(huán)境變量字典
            env = {}

            #調(diào)用應(yīng)用的相應(yīng)方法,完成動(dòng)態(tài)數(shù)據(jù)的獲取
            bodyContent = self.application(env, self.startResponse)

            #組織數(shù)據(jù)發(fā)送給客戶端
            self.finishResponse(bodyContent)


    def startResponse(self, status, response_headers):
        serverHeaders = [
            ('Date', 'Tue, 31 Mar 2016 10:11:12 GMT'),
            ('Server', 'WSGIServer 0.2'),
        ]
        self.headers_set = [status, response_headers + serverHeaders]

    def finishResponse(self, bodyContent):
        try:
            status, response_headers = self.headers_set
            #response的第一行
            response = 'HTTP/1.1 {status}\r\n'.format(status=status)
            #response的其他頭信息
            for header in response_headers:
                response += '{0}: {1}\r\n'.format(*header)
            #添加一個(gè)換行,用來(lái)和body進(jìn)行分開
            response += '\r\n'
            #添加發(fā)送的數(shù)據(jù)
            for data in bodyContent:
                response += data

            self.clientSocket.send(response)
        finally:
            self.clientSocket.close()

#設(shè)定服務(wù)器的端口
serverAddr = (HOST, PORT) = '', 8888
#設(shè)置服務(wù)器靜態(tài)資源的路徑
documentRoot = './html'
#設(shè)置服務(wù)器動(dòng)態(tài)資源的路徑
pythonRoot = './wsgiPy'

def makeServer(serverAddr, application):
    server = WSGIServer(serverAddr)
    server.setApp(application)
    return server

def main():

    if len(sys.argv) < 2:
        sys.exit('請(qǐng)按照要求,指定模塊名稱:應(yīng)用名稱,例如 module:callable')

    #獲取module:callable
    appPath = sys.argv[1]
    #根據(jù)冒號(hào)切割為module和callable
    module, application = appPath.split(':')
    #添加路徑套sys.path
    sys.path.insert(0, pythonRoot)
    #動(dòng)態(tài)導(dǎo)入module變量中指定的模塊
    module = __import__(module)
    #獲取module變量中指定的模塊的,application變量指定的屬性
    application = getattr(module, application)
    httpd = makeServer(serverAddr, application)
    print('WSGIServer: Serving HTTP on port %d ...\n'%PORT)
    httpd.serveForever()

if __name__ == '__main__':
    main()

下一篇文章為:→4.1.7應(yīng)用程序示例
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容