Django(一):從socket到MVC


一、socket的http套路

  web應用本質上是一個socket服務端,用戶的瀏覽器是一個socket客戶端。socket處在應用層與傳輸層之間,是操作系統中I/O系統的延伸部分(接口),負責系統進程和應用之間的通信。

  HTTP協議又稱超文本傳輸協議。

1 //瀏覽器發送一個HTTP請求;
2 //服務器收到請求,根據請求信息,進行函數處理,生成一個HTML文檔;
3 //服務器把HTML文檔作為HTTP響應的Body發送給瀏覽器;
4 //瀏覽器收到HTTP響應,從HTTP Body取出HTML文檔並顯示;
View Code

  1、客戶端套路解析

 1 import socket, ssl
 2 # socket 是操作系統用來進行網絡通信的底層方案,用來發送/接收數據
 3 
 4 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 5 # socket.AF_INET表示是ipv4協議,socket.SOCK_STREAM表示是tcp協議,這兩個值是默認的。
 6 # s = socket.socket()
 7 # 上面只能連接http,如果連接https,需要用s = ssl.wrap_socket(socket.socket())
 8 
 9 host, port  = ("g.cn", 80)
10 s.connect((host, port))  # 連接主機,參數是主機的和端口
11 
12 ip, port = s.getsockname()
13 print('本機 ip 和 port {} {}'.format(ip, port))  # 查看本機的ip和端口
14 
15 # 構造一個http請求
16 http_request = 'GET / HTTP/1.1\r\nhost:{}\r\n\r\n'.format(host)
17 
18 # 發送HTTP請求給服務器
19 # send 函數只接收bytes作為參數,所以要重編碼為utf-8。實際上,web數據傳送都是utf-8編碼的字節流數據。
20 
21 request = http_request.encode(encoding='utf_8', errors='strict')
22 print("發送請求", request)
23 s.send(request)
24 
25 
26 # 接收服務器的相應數據
27 response = s.recv(1024)   # buffer_size=1024,只接收1024個字節,多余的數據就不接收了。粘包。
28 
29 # 輸出響應的數據,bytes類型
30 # print("響應", response)
31 # 再講response的utf-8編碼的字節流數據進行解碼(實際上是轉換成unicode編碼的字符串,因為讀進了內存)。
32 print("響應的 str 格式: ", end="\r\n")
33 print(response.decode(encoding='utf-8'))
View Code

  2、服務器套路解析

 1 import socket
 2 
 3 host, port = '', 2000
 4 # 服務器的host為空字符串,表示接受任意ip地址的連接
 5 
 6 s  = socket.socket()
 7 s.bind((host, port))  # 監聽
 8 
 9 # 用一個無線循環來接受數據
10 while True:
11     print("before listen")
12     s.listen(5)
13     
14     # 接收請求
15     connection, address = s.accept()
16     # connection是一個socket.socket對象
17     print("after listen")
18     
19     # 接收請求
20     request = connection.recv(1024)  # 只接收1024個字節
21     print("ip and request, {}\n{}".format(address, request.decode("utf-8")))
22     
23     # 構造響應
24     response = b"HTTP/1.1 200 OK\r\n\r\n<h1>Hello World!</h1>"
25     
26     # 用sendall發送響應數據
27     connection.sendall(response)
28     
29     # 關閉連接
30     connection.close()
31     
View Code

  在瀏覽器中輸入localhost:2000,看到Hello World。后台打印的結果如下:

 1 before listen
 2 after listen
 3 ip and request, ('127.0.0.1', 54275)
 4 GET / HTTP/1.1
 5 Host: localhost:2000
 6 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:59.0) Gecko/20100101 Firefox/59.0
 7 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
 8 Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
 9 Accept-Encoding: gzip, deflate
10 Cookie: username-localhost-8888="2|1:0|10:1524886551|23:username-localhost-8888|44:ZTc2ZjE3MjIxMTMwNDIxYzg3OTZmMDlkMDdhNzhjMjI=|b432650e1e450be30083dd567068aebd47dc8d5b7167b068610af60db4c5a35d"; _xsrf=2|fc2cd1bd|88c10f771944fea069e65d5e767b6621|1524882104
11 Connection: keep-alive
12 Upgrade-Insecure-Requests: 1
View Code

  粘包處理

1 粘包處理:
2 
3 buffer_size = 1023
4 r = b''
5 while True:
6     request = connection.recv(buffer_size)
7     r += request
8     if len(request) < buffer_size:
9     break
View Code

  3、HTTP請求內容解析

 1 """
 2 HTTP頭
 3 http://localhost:2000/,瀏覽器默認會隱藏http://和末尾的/
 4 
 5 GET / HTTP/1.1
 6 # GET表示請求方式, / 表示請求的資源路徑, HTTP/1.1 協議版本
 7 
 8 Host: localhost:2000
 9 # 主機地址和端口
10 
11 Connection: keep-alive
12 # keep-alive保持連接狀態,它表示http連接(不用TCP請求斷開再請求);close每次離開就關閉連接
13 
14 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:59.0) Gecko/20100101 Firefox/59.0
15 # 用戶代理,瀏覽器標識。可以偽造瀏覽器。
16 
17 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
18 # 瀏覽器接收的數據類型。左邊是數據類型,右邊是解析時的權重(優先級)。
19 
20 Accept-Encoding: gzip, deflate
21 # 可解壓的壓縮文件類型;只表示能解壓該類型的壓縮文件,不代表拒絕接收其它類型的壓縮文件。
22 
23 Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
24 # 支持的語言類型及其解析權重。
25 
26 Cookie: username-localhost-8888="2|1:0|10:1524886551|23:username-localhost-8888|44:ZTc2ZjE3MjIxMTMwNDIxYzg3OTZmMDlkMDdhNzhjMjI=|b432650e1e450be30083dd567068aebd47dc8d5b7167b068610af60db4c5a35d"; _xsrf=2|fc2cd1bd|88c10f771944fea069e65d5e767b6621|1524882104
27 # 瀏覽器緩存。
28 
29 /favicon.ico
30 # url地址圖標,非必須。
31 
32 # Header里可以添加任意的內容。
33 """
View Code

二、socket的udp和tcp套路

  1、udp的客戶端和服務端寫法

  客戶端

 1 import socket
 2 # upd鏈接
 3 # SOCK_DGRAM:數據報套接字,主要用於UDP協議
 4 udpSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
 5 
 6 # 關閉防火牆
 7 # 同一網段(局域網)下,主機的ip地址和端口號.
 8 sendAddr = ('192.168.10.247', 8080)
 9 
10 # 綁定端口:寫的是自己的ip和固定的端口,一般是寫在sever端.
11 udpSocket.bind(('', 9900))
12 
13 # sendData = bytes(input('請輸入要發送的數據:'), 'gbk')
14 # gbk, utf8, str
15 sendData = input('請輸入要發送的數據:').encode('gbk')
16 
17 # 使用udp發送數據,每一次發送都需要寫上接收方的ip地址和端口號
18 udpSocket.sendto(sendData, sendAddr)
19 # udpSocket.sendto(b'hahahaha', ('192.168.10.247', 8080))
20 
21 udpSocket.close()
View Code

  服務端

 1 import socket
 2 
 3 udpSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
 4 
 5 # 接收方一般需要綁定端口
 6 # ''表示自己電腦的任何一個ip,即無線和有限同時連接或者電腦有不同的網卡(橋接),會有多個ip.
 7 # 綁定自己的端口
 8 bindAddr = ('', 7788)
 9 udpSocket.bind(bindAddr)
10 
11 recvData = udpSocket.recvfrom(1024)
12 # print(recvData)
13 print(recvData[0].decode('gbk'))
14 
15 udpSocket.close()
16 # recvData的格式:(data, ('ip', 端口)).它是一個元組,前面是數據,后面是一個包含ip和端口的元組.
View Code

  2、tcp的客戶端和服務端寫法

  客戶端

 1 import socket
 2 
 3 tcpClient = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 4 
 5 serverAddr = ('192.168.10.247', 8899)
 6 
 7 # tcp的三次握手,寫進了這一句話
 8 tcpClient.connect(serverAddr)
 9 
10 sendData = input('')
11 
12 # 直接用send就行了,udp是用sendto
13 tcpClient.send(sendData.encode('gbk'))
14 
15 recvData = tcpClient.recv(1024)
16 
17 print('接收到的數據為:%s' % recvData.decode('gbk'))
18 
19 tcpClient.close()
20 
21 # 為什么用send而不是sendto?因為tcp連接是事先鏈接好了,后面就直接發就行了。前面的connect已經連接好了,后面直接用send發送即可。
22 # 而udp必須用sendto,是發一次數據,連接一次。必須要指定對方的ip和port。
23 # 相同的道理,在tcpServer端,要寫recv,而不是recvfrom來接收數據
View Code

  服務端

 1 import socket
 2 tcpServer = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 3 tcpServer.bind(('', 8899))
 4 tcpServer.listen(5)
 5 
 6 # tcp的三次握手,寫進了這一句話當中
 7 tcpClient, tcpClientInfo = tcpServer.accept()
 8 # tcpServer.accept(),不需要寫ip,可以接收多個客戶端的。但事先要綁定端口和接入的客戶端的數量
 9 # client 表示接入的新的客戶端
10 # clientInfo 表示接入的新的客戶端的ip和端口port
11 
12 recvData = tcpClient.recv(1024)
13 print('%s: %s' % (str(tcpClientInfo), recvData.decode('gbk')))
14 
15 # tcp的四次握手,寫進了這一句話
16 tcpClient.close()
17 tcpServer.close()
18 
19 # tcpServer.accept():等待客戶端的接入,自帶堵塞功能:即必須接入客戶端,然后往下執行
20 # tcpClient.recv(1024): 也是堵塞,不輸入數據就一直等待,不往下執行.
21 # tcpServer創建了兩個套接字,一個是Server,另一個是tcpClient.Server負責監聽接入的Client,再為其創建專門的tcpClient進行通信.
View Code

  3、服務端開啟循環和多線程模式

  開啟循環

 1 import socket
 2 
 3 Server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 4 
 5 Server.bind(('', 9000))
 6 Server.listen(10)
 7 
 8 while True:
 9     # 如果有新的客戶端來鏈接服務器,那么就產生一個新的套接字專門為這個客戶端服務
10     serverThisClient, ClientInfo = Server.accept()
11     print('Waiting connect......')
12 
13     # 如果客戶發送的數據是空的,那么斷開連接
14     while True:
15         recvData = serverThisClient.recv(1024)
16         if len(recvData) > 1:
17 
18             print('recv: %s' % recvData.decode('gbk'))
19 
20             sendData = input('send: ')
21             serverThisClient.send(sendData.encode('gbk'))
22         else:
23             print('再見!')
24             break
25     serverThisClient.close()
View Code

  多線程寫法

 1 from threading import Thread
 2 import socket
 3 # 收數據,然后打印
 4 def recvData():
 5     while True:
 6         recvInfo = udpSocket.recvfrom(1024)
 7         print('%s:%s' % (str(recvInfo[1]), recvInfo[0].decode('gbk')))
 8 
 9 # 檢測鍵盤,發數據
10 def sendData():
11     while True:
12         sendInfo = input('')
13         udpSocket.sendto(sendInfo.encode('gbk'), (destIp, destPort))
14 
15 udpSocket = None
16 destIp = ''
17 destPort = 0
18 # 多線程
19 def main():
20 
21     global udpSocket
22     global destIp
23     global destPort
24 
25     destIp = input('對方的ip: ')
26     destPort = int(input('對方的端口:'))
27 
28     udpSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
29     udpSocket.bind(('', 45678))
30 
31     tr = Thread(target=recvData)
32     ts = Thread(target=sendData)
33 
34     tr.start()
35     ts.start()
36 
37     tr.join()
38     ts.join()
39 if __name__ == '__main__':
40     main()
View Code

三、socket 獲取 html

  目標:獲取https://movie.douban.com/top250整個網頁。

  過程:

    1.構造GET請求頭,包括: https協議處理,movie.douban.com為host,port默認為443,/top250為請求的url。

    2.粘包接收字節流並進行解析,返回狀態碼、響應頭、響應體。

  實例代碼:

  1 import socket, ssl
  2 
  3 
  4 """
  5 https 請求的默認端口是 443,https 的 socket 連接需要 import ssl,並且使用 s = ssl.wrap_socket(socket.socket()) 來初始化
  6 
  7 HTTP 協議的 301 狀態會在 HTTP 頭的 Location 部分告訴你應該轉向的 URL
  8 如果遇到 301, 就請求新地址並且返回
  9         HTTP/1.1 301 Moved Permanently
 10         ...
 11         Location: https://movie.douban.com/top250
 12 """
 13 
 14 
 15 def parse_url(url):
 16     protocol = 'http'
 17     
 18     if url[:7] == 'http://':
 19         u = url.split("://")[1]
 20     elif url[:8] == "https://":
 21         protocol = "https"
 22         u = url.split("://")[1]
 23     else:
 24         u = url
 25     
 26     # https://g.cn:1234/hello/world
 27     # 這里host就是g.cn:1234
 28     # 這里path就是/hello/world
 29     
 30     # 檢查host和path
 31     i = u.find('/')
 32     if i == -1:
 33         host = u
 34         path = '/'
 35     else:
 36         host = u[:i]
 37         path = u[i:]
 38     
 39     # 檢查端口
 40     port_dict = dict(
 41         http=80,
 42         https=443,
 43     )
 44     # 默認端口
 45     port = port_dict[protocol]
 46     if ":" in host:
 47         h = host.split(":")
 48         host = h[0]             # 到這里獲取ip
 49         port = int(h[1])        # 獲取端口
 50     return protocol, host, port, path
 51 
 52 
 53 def socket_by_protocol(protocol):
 54     """根據協議返回一個socket實例"""
 55     if protocol == 'http':
 56         s = socket.socket()
 57     else:
 58         # https協議要用到ssl
 59         s = ssl.wrap_socket(socket.socket())
 60     return s
 61         
 62 def response_by_socket(s): 
 63     """s是一個socket實例,返回這個socket讀取的所有數據"""
 64     response = b''
 65     buffer_size = 1024
 66     while True:
 67         r = s.recv(buffer_size)
 68         if len(r) == 0:
 69             break
 70         response += r
 71     return response
 72 
 73 def parsed_response(r):
 74     """
 75     把response解析出 狀態碼 headers body 返回
 76     狀態碼是 int
 77     headers是 dict
 78     body是 str
 79     """
 80     header, body = r.split('\r\n\r\n', 1)     # split 1 只分割1次
 81     h = header.split('\r\n')
 82  
 83     # HTTP/1.1 200 OK
 84     status_code = h[0].split()[1]   # 空格切分,取中間的狀態碼
 85     status_code= int(status_code)
 86     
 87     headers = {}
 88     for line in h[1: ]:
 89         k, v = line.split(": ")
 90         headers[k] = v
 91     return status_code, headers, body
 92 
 93 def get(url):
 94     """用get請求url並返回響應"""
 95     protocol, host, port, path = parse_url(url)
 96     print(protocol, host, port, path)
 97     # 根據protocol確定socket方式
 98     s = socket_by_protocol(protocol)
 99     s.connect((host, port))
100     
101     # 構造請求,注意不要用keep-alive,因為服務器不會主動關閉連接
102     request = 'GET {} HTTP/1.1\r\nhost: {}\r\nconnection: close\r\n\r\n'.format(path, host)
103     
104     # 發送請求
105     s.send(request.encode(encoding='utf_8', errors='strict'))
106     
107     # 獲取響應
108     response = response_by_socket(s)   # 接收所有的數據
109     r = response.decode('utf-8')
110     
111     status_code, headers, body = parsed_response(r)  # 解析狀態碼,請求頭和請求體
112     
113     if status_code in [301, 302]:    # 301和302是重定向,要遞歸進行尋址
114         url = headers["Location"]
115         return get(url)
116     return status_code, headers, body    
117 
118 def main():
119     url = 'https://movie.douban.com/top250'
120     status_code, headers, body = get(url)
121     print(status_code, headers, body)
122 
123 if __name__ == '__main__':
124     main()
125     
View Code

  缺陷:這里沒有對html文檔進行處理,包括html文檔中所需內容(node節點)的解析和保存。可以使用bs4進一步處理。

    注意:request請求必須要確保無誤,否則會很容易出錯。

四、socket寫web服務

  這里的內容極其重要。一切web框架的本質是socket。Django和Flask的框架都是在下面最簡功能上進行拆分解耦建立起來的。

 1 import socket, functools
 2 from docutils.parsers.rst.directives import encoding
 3 
 4 #  包裹print,禁止它的一些額外的功能
 5 def log(*args, **kwargs):
 6     print("LOG: ", *args, **kwargs)
 7 # 禁止函數的默認返回, func = lambda x: x, print = func(print)。這個在flask的werkzeug.local中用了幾十次。
 8 
 9 
10 def route_index():
11     """主頁的處理函數, 返回響應"""
12     header = 'HTTP/1.x 200 OK \r\nContent-Type: text/html\r\n'
13     body = '<h1>Hello World.</h1><img src="dog.gif"/>'
14     r = header + '\r\n' + body
15     return r.encode(encoding='utf-8')
16 
17 def route_image():
18     """返回一個圖片"""
19     with open('dog.gif', mode='rb') as f:
20         header = b'HTTP/1.x 200 OK\r\nContent-Type: image/gif\r\n\r\n'
21         img = header + f.read()
22         return img
23 
24 def page(html):
25     with open(html, encoding="utf-8") as f:
26         return f.read()
27     
28     
29 def route_msg():
30     """返回一個html文件"""
31     header = 'HTTP/1.x 200 OK \r\nContent-Type: text/html\r\n'
32     body = page("html_basic.html")
33     r = header + '\r\n' + body
34     return r.encode(encoding='utf-8')
35 
36 
37 def error(code=404):
38     e = {
39         404: b'HTTP/1.x 404 NOT FOUND\r\n\r\n<h1>Page Not Found</h1>',
40     }
41     return e.get(code, b'')
42 
43 
44 def response_for_path(path):
45     """根據path調用相應的處理函數,沒有處理的path會返回404"""
46     r = {
47         '/': route_index,
48         '/dog.gif': route_image,
49         '/msg': route_msg,
50     }
51     response = r.get(path, error)   # 注意,這里用dict的get方法設置了不存在時的默認值
52     return response()
53     
54 def run(host="", port=3000):
55     """啟動服務器"""
56     with socket.socket() as s:
57         # 使用with可以保證程序終端的時候正確關閉socket,釋放占用的端口
58         s.bind((host, port))
59         
60         while True:
61             s.listen(5)
62             
63             connection, address = s.accept()
64             request = connection.recv(1024)
65             request = request.decode('utf-8')
66             log('ip and request, {}\n{}'.format(address, request))
67             
68             try:
69                 path = request.split()[1]
70                 response = response_for_path(path)  # 用response_for_path函數來根據不同的path,生成不同的響應內容
71                 connection.sendall(response)
72             
73             except Exception as e:
74                 log("error ", e)
75             
76             connection.close()
77     
78 
79 def main():
80     config = dict(
81         host='',
82         port=4000,
83     )
84     run(**config)
85     
86 if __name__ == '__main__':
87     main()
View Code

  用到的圖片直接放在當前.py同一目錄下即可。html也是同級目錄,內容如下:

 1 <!DOCTYPE html>
 2 <!-- 注釋是這樣的, 不會被顯示出來 -->
 3 <!--
 4     html 格式是瀏覽器使用的標准網頁格式
 5     簡而言之就是 標簽套標簽
 6 -->
 7 <!-- html 中是所有的內容 -->
 8 <html>
 9     <!-- head 中是放一些控制信息, 不會被顯示 -->
10     <head>
11         <!-- meta charset 指定了頁面編碼, 否則中文會亂碼 -->
12         <meta charset="utf-8">
13         <!-- title 是瀏覽器顯示的頁面標題 -->
14         <title>例子 1</title>
15     </head>
16     <!-- body 中是瀏覽器要顯示的內容 -->
17     <body>
18         <!-- html 中的空格是會被轉義的, 所以顯示的和寫的是不一樣的 -->
19         <!-- 代碼寫了很多空格, 顯示的時候就只有一個 -->
20         很         好普通版
21         <h1>很好 h1 版</h1>
22         <h2>很好 h2 版</h2>
23         <h3>很好 h3 版</h3>
24         <!-- form 是用來給服務器傳遞數據的 tag -->
25         <!-- action 屬性是 path -->
26         <!-- method 屬性是 HTTP方法 一般是 get 或者 post -->
27         <!-- get post 的區別上課會講 -->
28         <form action="/" method="get">
29             <!-- textarea 是一個文本域 -->
30             <!-- name rows cols 都是屬性 -->
31             <textarea name="message" rows="8" cols="40"></textarea>
32             <!-- button type=submit 才可以提交表單 -->
33             <button type="submit">GET 提交</button>
34         </form>
35         <form action="/" method="post">
36             <textarea name="message" rows="8" cols="40"></textarea>
37             <button type="submit">POST 提交</button>
38         </form>
39     </body>
40 </html>
View Code

 運行上述py程序,訪問localhost:4000/msg,在get和post輸入框里分別輸入內容並點擊發送。可以看到,get請求的參數包含在請求頭里,post請求的參數包含在請求體里。這需要分別處理並獲取參數。

五、從socket到web框架

  有了上述內容,整個url請求的處理流程如下圖所示。

  

  創建python package。創建以下幾個py文件。(https://github.com/ZJingyu/socket_learning)

    - web

      - static: 靜態文件

      - templates: html文件

      - server: 主要負責監聽socket連接和接收請求,並對請求進行解析,傳遞給不同的處理函數。

      - routes: url對應的處理函數。

      - models: 數據交互的處理。

  當然,對於models和routes都是可以再拆分。如:

    - web

      - static

      - templates

      - db

      - views.py: 將routes改名為views.py,刪掉route_dict。

      - urls.py: 把route_dict放進來,從views.py中導入所有視圖函數。

      - models:新建名為models的python package,創建Message.py和User.py,將原models.py中的三個類分開,Model放進__init__.py里。

        __init__.py: Model類

        - Message.py: Message類

        - User.py: User類

 1 # __init__.py
 2 
 3 import json
 4 
 5 def save(data, path):
 6     """把一個dict或者list寫入文件"""
 7 
 8     # indent是縮進, ensure_ascii=False用於保存中文
 9     s = json.dumps(data, indent=2, ensure_ascii=False)
10     with open(path, 'w+', encoding='utf-8') as f:
11         print('save', path, s, data)
12         f.write(s)
13 
14 
15 def load(path):
16     """從一個文件中載入數據並轉化為dict或者list"""
17     with open(path, 'r', encoding='utf-8') as f:
18         s = f.read()
19         print('load', s)
20         return json.loads(s)
21 
22 
23 # Model是用於存儲數據的基類
24 class Model(object):
25     @classmethod
26     def db_path(cls):
27         classname = cls.__name__
28         path = '{}.txt'.format(classname)
29         return path
30 
31     @classmethod
32     def new(cls, form):
33         m = cls(form)  # 初始化實例 m = Model(form)
34         return m
35 
36     @classmethod
37     def all(cls):
38         path = cls.db_path()
39         models = load(path)
40         ms = [cls.new(m) for m in models]
41         return ms
42 
43     def save(self):
44         models = self.all()
45         print('models', models)
46         models.append(self)
47         l = [m.__dict__ for m in models]
48         path = self.db_path()
49         save(l, path)
50 
51     def __repr__(self):
52         classname = self.__class__.__name__
53         properties = ['{}: ({})'.format(k, v) for k, v in self.__dict__.items()]
54         s = '\n'.join(properties)
55         return '< {}\n{} >\n'.format(classname, s)
View Code
1 # Message.py
2 from . import Model
3 
4 # 定義一個class用於保存message
5 class Message(Model):
6     def __init__(self, form):
7         self.author = form.get('author', "")
8         self.message = form.get('message', "")
View Code
 1 # User.py
 2 from . import Model
 3 
 4 # 以下兩個類用於實際的數據處理
 5 class User(Model):
 6     def __init__(self, form):
 7         self.username = form.get('username', "")
 8         self.password = form.get('password', "")
 9 
10     def validate_login(self):
11         return self.username == "gua" and self.password == "123"
12 
13     def validate_register(self):
14         return len(self.username) > 2 and len(self.password) > 2
View Code

    當然,,server也可以再拆分成server和manage的。將serve.py中的if main 放到manage.py去執行。

  上面這些雖然簡陋,但是實現了socket搭建web服務器的基本邏輯和功能,有助於梳理web服務的流程。原理在手,一切的web框架不外乎如是。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM