最终版的Web(Python实现)

天啦,要考试了,要期末考试了,今天把最终版的Python搭建Web代码先写这里记下了。详细的过程先不写了。

这次是在前面的基础上重写 HTTPServer 与 BaseHTTPRequestHandler,主要利用 python 提供

的 socket 进行编程,从而实现消息的接收与相应;然后再接着引入多线程,分别处理来自客户
端的请求;最后实现根据客户端传递的参数动态生成页面的功能。

主要步骤如下:

一、 .重写 HTTPServer 与 BaseHTTPRequestHandler
Python socket 编程流程(服务器端) :
1. 第一步是创建 socket 对象。调用 socket 构造函数。如:
socket = socket.socket( family, type )
family 参数代表地址家族, 可为 AF_INET 或 AF_UNIX。 AF_INET 家族包括 Internet
地址,AF_UNIX 家族用于同一台机器上的进程间通信。
type 参数代表套接字类型,可为 SOCK_STREAM(流套接字)和 SOCK_DGRAM(数
据报套接字)。
2. 第二步是将socket绑定到指定地址。 这是通过socket对象的bind方法来实现的:
socket.bind( address )
由 AF_INET 所创建的套接字,address 地址必须是一个双元素元组,格式是
(host,port)。host 代表主机,port 代表端口号。如果端口号正在使用、主机名不正
确或端口已被保留,bind 方法将引发 socket.error 异常。
3. 第三步是使用 socket 套接字的 listen 方法接收连接请求。
socket.listen( backlog )
backlog 指定最多允许多少个客户连接到服务器。 它的值至少为 1。 收到连接请求后,
这些请求需要排队,如果队列满,就拒绝请求。
4. 第四步是服务器套接字通过 socket 的 accept 方法等待客户请求一个连接。
connection, address = socket.accept()
调 用 accept 方法时,socket 会时入“waiting”状态。客户请求连接时,方法建立连
接并返回服务器。 accept 方法返回一个含有两个元素的 元组(connection,address)。
第一个元素 connection 是新的 socket 对象,服务器必须通过它与客户通信;第二
个元素 address 是客户的 Internet 地址。
5. 第五步是处理阶段, 服务器和客户端通过 send 和 recv 方法通信(传输 数据)。 服
务器调用 send,并采用字符串形式向客户发送信息。send 方法返回已发送的字符
个数。服务器使用 recv 方法从客户接收信息。调用 recv 时,服务器必须指定一个
整数,它对应于可通过本次方法调用来接收的最大数据量。recv 方法在接收数据时
会进入“blocked”状态,最后返回一个字符 串,用它表示收到的数据。如果发送的数
据量超过了 recv 所允许的,数据会被截短。多余的数据将缓冲于接收端。以后调用
recv 时,多余的数据会从缓冲区 删除(以及自上次调用 recv 以来,客户可能发送的
其它任何数据)。
6. 传输结束,服务器调用 socket 的 close 方法关闭连接。

整个代码块儿如下:

注释有点乱, 中英文结合。。

Test.py

# -*-coding:utf-8 -*-
import BaseHTTPServer
import os
import socket
import subprocess
import threading

from datetime import datetime

class ServerException( Exception ):
    pass

    #
    # 重写 HTTPServer 与 BaseHTTPRequestHandler,主要利用 python 提供
    # 的 socket 进行编程,从而实现消息的接收与相应;然后再接着引入多线程,分别处理来自客户
    # 端的请求;最后实现根据客户端传递的参数动态生成页面的功能。

# step1:reWrite HttpServer and BaseHTTPRequestHandler

class HttpServer:
    def __init__(self, serverAddr, RequestHandler):
        self.serverAddr = serverAddr
        self.requestHandler = RequestHandler

    def serve_forever(self):
        #    1. create socket object(对象), call socket create function
        server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        # 1family=AF_INET,type=SOCK_STREAM
        server_sock.bind(self.serverAddr)
        # 2. call socket bind, aim to bind socket to pointed address
        # address must be a two-elements yuanzu, style is (host, port)
        # host stands for port number. if port number is in using        #、host name is wrong or port number has been saved, bind way will
        # bring socket.error yi chang
        server_sock.listen(10)
        # 3.  using socket‘s listen way to receive connect request
        # listen parament backlog=10:point allow no more than 10 clients
        # can connect to server. its value at least is 1. when received
        # request, those requests need pai dui,if list full, then refuse request

        while True:
            print ‘waiting for connection...‘
            clientsock, addr = server_sock.accept()
            # 4. server socket wait for client to request a connection
            # when call accept() function, socket will come into "wating"
            # states. when client request connection,function create
            # connection and return server..
            # accept function return with two elements
            # (connection, address)., the first connection is new socket‘s
            # object, server must through it to tong xin with client.
            # the second element address is clients‘ Internet address
            print ‘received from :‘, addr
            thread = threading.Thread(target=self.startThread, args=(clientsock, addr,))
            thread.setDaemon(True)
            thread.start()
            # handler = RequestHandler(clientsock, addr,self)

        server_sock.close()

    def startThread(self, clientsock, addr):
        handler = RequestHandler(clientsock, addr, self)

class HttpRequestHandler:
    bufsize = 1024

    def __init__(self, clientsock, addr):
        self.cliensock = clientsock
        self.client_address = addr
        self.date_time_string = datetime.now()
        self.analyze() # http head part analyze

    def analyze(self):
        # receive dates, bufsize points to read dates num one time
        """

        :type self: object

        """
        data = self.cliensock.recv(self.bufsize)
        # print‘receive ------->%s\n%s‘ %(datetime.now(), data)

        # chrome sometimes will send two request consist, tne second is null, reason is unknow
        if data.repalce(" ", "") == "":
            print "data is null"
            return
        data = data.split(‘\r\n‘)
        # first line is "GET/something.html?a=1&b=2 HTTP/1.1
        firstLine = data[0]
        arr = firstLine.split(‘ ‘)
        self.command = arr[0]
        self.protocol = arr[2]
        if ‘?‘ in arr[1]:
            # path put absolute way
            self.path, self.paramStr = arr[1].spilt(‘?‘)
        else:
            self.path = arr[1]
            self.paramStr = None

            # put the remain of head information in heades‘s dictionary in the way of key value
            # Accept-Language : zh - cn
            # Connection : Keep - Alive
            # Host : Localhost
            # Accept - Encoding : gzip, deflate
            self.headers = {}
            for line in data[1:]:
                if ‘:‘ in line:
                    key, value = line.split(‘:‘, 1)
                    self.headers[key] = value

                    # call function to deal with, this function has come in the first
            self.do_GET()
            # time.sleep(30)
            # when this function receive data, first feng li data
            # char string as th rule of ‘\r\n‘
            # then ti qu first line, that is "GET/something.html?a=1&b=2 HTTP/1.1
            # then analyze it , put it to the variable

    # path

    http_response = "HTTP/1.1"

    def send_response(self, status):
        if status == 200:
            self.http_response += "200" + " " + "OK"
        elif status == 404:
            self.http_response += "400" + " " + "Not Found"
        self.http_response += ‘\r\n‘

    # "Content_Type", "text/html"
    # "Content-Length", Length

    def send_heade(self, key, value):
        self.http_response += str(key) + ": " + str(value) + ‘\r\n‘

    def end_headers(self):
        self.http_response += ‘\r\n‘

    def write(self, page):
        self.http_response += str(page)
        self.clientsock.send(self.http_response)
        self.cliensock.close()

        # those functions are pin zhuang http_response char string
        # as the rule of response head style

class RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
    """dealt with and return page"""
    # page model
    Page = ‘‘‘
    <html>
    <body>
    <table border=2s>
   <tr> <td>Header</td> <td>Value</td> </tr>
<tr> <td>Date</td><td> and time</td> <td>{date_time}</td> </tr>
<tr> <td>Client host</td> <td>{client_host}</td> </tr>
<tr> <td>Client port</td> <td>{client_port}</td> </tr>
<tr> <td>Command</td> <td>{command}</td> </tr>
<tr> <td>Path</td> <td>{path}</td> </tr>
</table>
</body>
    </html>
    ‘‘‘
    Error_Page = """    <html>
    <body>
    <h1>Error accessing {path}</h1>
    <p>{msg}</p>
    </body>
    </html>
    """

    def handle_error(self, msg):
        content = self.Error_Page.format( path=self.path, msg=msg )
        self.send_content( content, 404 )

    def handle_file(self, full_path):
        # 处理 python 脚本
        if full_path.endswith(‘.py‘):
            # data 为脚本运行后的返回值
            data = subprocess.check_output([‘python‘, full_path, self.paramStr] )
            self.send_content(data)
            return
        try:
            with open(full_path, ‘rb‘) as reader:
                content = reader.read()
            self.send_content(content)
        except IOError as msg:
            msg = "‘{0}‘ cannot be read: {1}".format(self.path, msg )
            self.handle_error(msg)

    # deal with a request
    def do_GET(self):
        # type: () -> object
        try:
            full_path = os.getcwd() + self.path

            if not os.path.exists(full_path):
                raise ServerException("‘{0}‘ not found".format( self.path ) )
            elif os.path.isfile(full_path):
                self.handle_file(full_path)
                # 访问根路径
            elif os.path.isdir(full_path):
                # fullPath = os.path.join(fullPath, "index.html")
                full_path += "index.html"
                if os.path.isfile(full_path):
                    self.handle_file(full_path )
                else:
                    raise ServerException( "‘{0}‘ not found".format( self.path ) )
            else:
                raise ServerException( "Unknown object ‘{0}‘".format( self.path ) )
        except Exception as msg:
            self.handle_error(msg)

    @property
    def create_page(self):
        values = {
            ‘date_time‘: self.date_time_string( ),
            ‘client_host‘: self.client_address[0],
            ‘client_port‘: self.client_address[1],
            ‘command‘: self.command,
            ‘path‘: self.path
        }
        page = self.Page.format( **values )
        return page
        pass

    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(self.create_page)
        self.wfile.write(content)
        # self.write(page)
        pass

if __name__ == ‘__main__‘:
    serverAddr = (‘localhost‘, 5555)
    server = HttpServer(serverAddr, RequestHandler )
    server.serve_forever()

 

calc.py

import sys

paramStr = sys.argv[1]
paramArr = paramStr.split(‘&‘)
paramDict = {}
for param in paramArr:
    key, value = param.split(‘=‘)
    paramDict[key] = value

print ‘‘‘<html>
<body>
<p>a + b = {0}</p>
</body>
</html>‘‘‘.format((int(paramDict[‘a‘]) + int(paramDict[‘b‘])))

  index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>index</title>
</head>
<body>
   <h1>Index Page </h1>
   <p>I love Python, to be honest</p>

<table border=2s>
   <tr> <td>Header</td> <td>Value</td> </tr>
<tr> <td>Date</td><td> and time</td> <td>{date_time}</td> </tr>
<tr> <td>Client host</td> <td>{client_host}</td> </tr>
<tr> <td>Client port</td> <td>{client_port}</td> </tr>
<tr> <td>Command</td> <td>{command}</td> </tr>
<tr> <td>Path</td> <td>{path}</td> </tr>
</table>

<p>please input first number:</p>
<input>
<br>
<p>please input second number:</p>
<input>

<button>add</button>
</body>
</html>

 运行效果如图:

好好准备期末考了。。。。

 

时间: 2024-12-29 12:02:36

最终版的Web(Python实现)的相关文章

jQuery 3.0最终版发布,十大新特性眼前一亮

jQuery 3.0在日前发布了最终的全新版本.从2014年10月,jQuery团队对这个主要大版本进行维护开始,web开发者社区便一直在期待着这一刻的到来,终于在2016年6月他们迎来了这一个最终版www.lampbrother.net. 通过jQuery 3.0的版本更新说明,我们看到了一个保持着向后兼容的更轻便,更快速的jQuery.在本文中,我们将介绍一些令人眼前一亮的jQuery 3.0全新特性. 开始前的说明 如果你想要下载jQuery 3.0进行亲自实验,可以通过该页面进行下载.另

连续加班一周最终把所有的Python库整理出来了,愿各位早日学会Python!

我们直接开始主题,小伙伴们需要资料的话可以私信我回复01,可以获得大量PDF书籍和视频! Python常用的库简单介绍一下 fuzzywuzzy ,字符串模糊匹配. esmre ,正则表达式的加速器. colorama 主要用来给文本添加各种颜色,并且非常简单易用. Prettytable 主要用于在终端或浏览器端构建格式化的输出. difflib ,[Python]标准库,计算文本差异 . Levenshtein ,快速计算字符串相似度. Chardet 字符编码探测器,可以自动检测文本.网页

PSPInstance Object | Web Python

PSPInstance Object | Web Python The PSPInstance object is available to all PSP pages through the psp variable.PSPInstance Object | Web Python,布布扣,bubuko.com

HOWTO Use Python in the web — Python v3.0.1 documentation

HOWTO Use Python in the web - Python v3.0.1 documentation mod_python? People coming from PHP often find it hard to grasp how to use Python in the web. Their first thought is mostly mod_python because they think that this is the equivalent to mod_php.

结对项目--四则运算图形化最终版

四则运算器图形化最终版 (然而被我做成了奇怪的东西 组员:13070030张博文 13070033刘云峰 一.概念阶段 最初是想试试用android做个计算器app,无奈从零学起着实太赶,而且这个计划在试用了无比卡顿占内存的android studio后就彻底搁浅了. 然后就被路人谣传说MFC好用,无奈从零学起着实太赶,而且这个计划在无人指导的摸黑下也顺手搁浅了. 最终便沦为了EasyX旧传统,好歹有点基础,但果然还是不太甘心. 以及因为当初想做app,所以抠了iphone计算器的图想当UI,结

理解《JavaScript设计模式与开发应用》发布-订阅模式的最终版代码

最近拜读了曾探所著的<JavaScript设计模式与开发应用>一书,在读到发布-订阅模式一章时,作者不仅给出了基本模式的通用版本的发布-订阅模式的代码,最后还做出了扩展,给该模式增加了离线空间功能和命名空间功能,以达到先发布再订阅的功能和防止名称冲突的效果.但是令人感到遗憾的是最终代码并没有给出足够的注释.这让像我一样的小白就感到非常的困惑,于是我将这份最终代码仔细研究了一下,并给出了自己的一些理解,鉴于能力有限,文中观点可能并不完全正确,望看到的大大们不吝赐教,谢谢! 下面是添加了个人注释的

成为C++高手之最终版计算器

下面做我们的计算器最终版. 当前还存在的问题是用户只能算一次.如果有人买一个一次性计算器,那么他肯定是个土豪.我们的计算器不能只给土豪用,所以要改成可以反复使用的. 使用循环语句就可以了,但是循环哪些代码呢?从用户输入到打印出结果这个过程要反复执行,代码如是: enum OPT{ jia = 1, jian, cheng, chu }; int main(void) { //保存用户输入的数 int number1; int number2; int opt;//运算符 //循环从输入到输出结果

20172333 2017-2018-2 《程序设计与数据结构》实验2报告(最终版)

20172333 2017-2018-2 <程序设计与数据结构>实验2报告(最终版) 1.结对成员 李楠20172330 领航员:李楠 驾驶员:严域俊 成绩分配:五五开 2.相关测试过程及截图 [x] 完整一套流程截图(创建题目,中缀转后缀,计算后缀,对比答案,答案正确个数.) [x] 分数测试类单独测试截图 [x] 整数测试类单独测试截图 [x] 中缀转后缀单独测试截图 3.测试中遇到的问题及解决办法 这周主要问题所在:由于在最后计算测试类编写的时候运用的方法来自几个类的合并,导致了在输出答

python操作word(改课文格式)【最终版】

python操作word的一些方法,前面写了一些感悟,有点跑题,改了下题目,方便能搜索到.心急的可以直接拉到最后看代码,我都加了比较详细的注释. 从8.3号早上9点,到8.8号下午5点半下班,终于把这个python代码写出来了,这五天简直是废寝忘食(扯淡),每天查资料到半夜2点(其实是天太热,洗完澡又晾干就要一个多小时了,在这里吐槽下今年的夏天,2016年北京的7月份简直了,平生第一次长痱子,连去年都没用过的凉席都翻出来了). 好吧,扯得有点远了.因为工作需要,要批量修改一批rtf文件里的文字格