<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                [TOC] >[success] # 仿照網站請求 ~~~ 1.處理url,通過url 獲取 http/https host port path 四個參數 2.例如 http://www.hmoore.net/book, 首先獲取http/https,在吧獲取的連接 www.hmoore.net/book,在進行拆分,獲取域名和端口 ~~~ >[info] ## 編寫客戶端 >[danger] ##### 處理url ~~~ 1.socket 仿照瀏覽器處理,獲取服務器請求 2.對url拆分,成協議,host,端口,和文件目錄 3.利用find,來進行目錄拆分,獲取位置信息后,進行切片獲取 4.將固定的東西放在字典中,省去if判斷邏輯 ~~~ ~~~ def parsed_url(url): """ :param url: 獲取網址的url :return: 返回所需要的 http/https host port path 四個參數 """ # 獲取http 或者https protocol = "http" if url[:7] == "http://": u = url.split("://")[1] if url[:8] == "https://": u = url.split("://")[1] protocol = "https" else: u = url # 把端口加域名 和 網站的文件目錄分離 i = u.find("/") if i == -1: host = u path = "/" else: host = u[:i] path = u[i:] # 處理host port_dict = { 'http': 80, 'https': 443, } port = port_dict[protocol] if ":" in host: h = host.split(":") host = h[0] port = int(h[1]) return protocol, host, port, path ~~~ >[danger] ##### 嘗試編寫單元測試 ~~~ def test_parsed_url(): http = 'http' https = 'https' host = 'g.cn' path = '/' test_items = [ ('http://g.cn', (http, host, 80, path)), ('http://g.cn/', (http, host, 80, path)), ('http://g.cn:90', (http, host, 90, path)), ('http://g.cn:90/', (http, host, 90, path)), # ('https://g.cn', (https, host, 443, path)), ('https://g.cn:233/', (https, host, 233, path)), ] for t in test_items: url, expected = t u = parsed_url(url) e = "parsed_url ERROR, ({}) ({}) ({})".format(url, u, expected) assert u == expected, e ~~~ >[danger] ##### 編寫client ~~~ 1.拆分一個做協議判斷的方法socket_by_protocol 2.一個循環獲得服務器返回所有信息的方法response_by_socket 3.一個解析 header body 請求狀態碼的方法,巧妙利用元組可以被多個元素接受 4.在整體的大方法中,我們也可以用列表存儲代替if判斷 ~~~ ~~~ import socket,ssl def socket_by_protocol(protocol): """ 判斷使用http 還是https 協議 """ if protocol == "http": s = socket.socket() else: s = ssl.wrap_socket(socket.socket()) return s def response_by_socket(s): """ 參數是一個 socket 實例 返回這個 socket 讀取的所有數據 """ response = b'' buffer_size = 1024 while True: r = s.recv(buffer_size) if len(r) == 0: break response += r return response def parsed_response(r): """ 把 response 解析出 狀態碼 headers body 返回 狀態碼是 int headers 是 dict body 是 str """ header, body = r.split('\r\n\r\n', 1) h = header.split('\r\n') status_code = h[0].split()[1] status_code = int(status_code) headers = {} for line in h[1:]: k, v = line.split(': ') headers[k] = v return status_code, headers, body def get(url): protocol, host, port, path = parsed_url(url) s = socket_by_protocol(protocol) s.connect((host, port)) # 不用持續連接Connection: close request = 'GET {} HTTP/1.1\r\nHost: {}\r\nConnection: close\r\n\r\n'.format(path, host) s.send(request.encode("utf-8")) response = response_by_socket(s) r = response.decode("utf-8") parsed_response(r) status_code, headers, body = parsed_response(r) if status_code in [301, 302]: url = headers['Location'] return get(url) return status_code, headers, body ~~~ >[danger] ##### 服務端 -- server.py ~~~ 1.利用 with 去做socket 連接,為了當端口用完進行關閉 2.接受到客戶端訪問服務器的請求頭,對請求頭的路徑拆分出來 3.通過路由,將請求頭 傳遞到路由映射函數 4.response_for_path 路由映射的方法,通過字典存儲和路徑對應的,處理函數, 其中k 保存的是函數地址,這樣減少執行函數 5.在路由函數中利用字典get 的屬性返回404 函數 6.將數據返回給客戶端 ~~~ ~~~ def log(*args, **kwargs): """ 用這個 log 替代 print """ print('log', *args, **kwargs) def route_index(): """ 主頁的處理函數, 返回主頁的響應 """ header = 'HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n' body = '<h1>Hello Gua</h1><img src="/doge.gif">' r = header + '\r\n' + body return r.encode(encoding='utf-8') def page(name): with open(name, encoding='utf-8') as f: return f.read() def route_msg(): """ msg 頁面的處理函數 """ header = 'HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n' body = page('html_basic.html') r = header + '\r\n' + body return r.encode(encoding='utf-8') def route_image(): """ 圖片的處理函數, 讀取圖片并生成響應返回 """ with open('doge.gif', 'rb') as f: header = b'HTTP/1.1 200 OK\r\nContent-Type: image/gif\r\n' img = header + b'\r\n' + f.read() return img def error(code=404): """ 根據 code 返回不同的錯誤響應 目前只有 404 """ # 之前上課我說過不要用數字來作為字典的 key # 但是在 HTTP 協議中 code 都是數字似乎更方便所以打破了這個原則 e = { 404: b'HTTP/1.1 404 NOT FOUND\r\n\r\n<h1>NOT FOUND</h1>', } return e.get(code, b'') def response_for_path(path): """ 根據 path 調用相應的處理函數 沒有處理的 path 會返回 404 """ r = { '/': route_index, '/doge.gif': route_image, '/msg': route_msg, } response = r.get(path, error) return response() def run(host='', port=3000): """ 啟動服務器 """ # 初始化 socket 套路 # 使用 with 可以保證程序中斷的時候正確關閉 socket 釋放占用的端口 with socket.socket() as s: s.bind((host, port)) # 無限循環來處理請求 while True: # 監聽 接受 讀取請求數據 解碼成字符串 s.listen(5) connection, address = s.accept() request = connection.recv(1024) log('raw, ', request) request = request.decode('utf-8') log('ip and request, {}\n{}'.format(address, request)) try: # 因為 chrome 會發送空請求導致 split 得到空 list # 所以這里用 try 防止程序崩潰 path = request.split()[1] # 用 response_for_path 函數來得到 path 對應的響應內容 response = response_for_path(path) # 把響應發送給客戶端 connection.sendall(response) except Exception as e: log('error', e) # 處理完請求, 關閉連接 connection.close() def main(): # 生成配置并且運行程序 config = dict( host='', port=3000, ) # 如果不了解 **kwargs 的用法, 群里問或者看書/搜索 關鍵字參數 run(**config) if __name__ == '__main__': main() ~~~
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看