日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

网络编程补充

發布時間:2024/3/26 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 网络编程补充 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

網絡編程補充

  • 1.認識
  • 2.Socket網絡編程
  • 3.TCP通訊
  • 4.echo模型
  • 5.UDP
  • 6.UDP廣播
  • 7.HTTP
  • 8.HTTP響應
  • 9.建立響應目錄
  • 10.動態請求處理
  • 11.urllib3
  • 12.twisted模塊認識
  • 13.twisted開發TCP程序
  • 14.使用twisted開發UDP程序
  • 15.Deferred

1.認識

  • 網絡編程的核心功能就是 IO 操作
  • 兩臺主機的通信要保證兩點:
  • 線路暢通
  • 雙方遵守協議
  • 在進行網絡程序開發的過程中一般都會考慮兩種不同的開發模式:
  • C/S模式(Client/Server—客戶端/服務端架構)
  • 需要編寫兩套不同的程序(客戶端與服務端)
  • 項目維護需要進行兩套項目的維護,維護成本比較高
  • 但是這種程序一般使用特定的協議(TCP),特定的數據結構,隱藏的端口等,安全性比較高
  • B/S模式(Browser/Server–瀏覽器與服務端架構)
  • 基于WEB設計的一種架構,基于瀏覽器的形式作為客戶端進行訪問,
  • 在程序開發時,成本較低,用戶使用門檻較低
  • 但這種開發一般基于HTTP協議完成處理,安全性不高,使用的是80端口,極易遭到攻擊
  • OSI 7層模型 (開放式系統互聯)
  • 網絡程序開發不僅僅是一個簡單的數據交互過程,還包含一些數據的處理邏輯,而所有的網絡設備一定會由不同的硬件廠商生產,所以為了保證數據傳輸的可靠性以及標準性,就定義了 OSI 7層模型
  • No議成名稱描述
    1應用層提供網絡服務操作接口
    2表示層對要傳輸的數據進行處理,例如:數據編碼
    3會話層管理不同的通訊節點之間的連接信息
    4傳輸層建立不同節點之間的網絡連接,為數據追加段信息
    5網絡層將網絡地址映射為mac地址實現數據包轉發,為數據追加包信息
    6數據鏈路層將要發送的數據包轉換為數據幀,是其在不可靠的物理鏈路上進行可靠的數據傳輸,為數據追加幀信息
    7物理層利用物理設備實現數據的傳輸(二進制數據傳輸)
  • 有了這7層不同的網絡數據的處理分類,所以任何的硬件廠商生產的設備(不管加入多少輔助技術),其核心是不變的
  • Python屬于高級語言,所以對于所有的網絡程序開發不可能讓開發者自行處理具體的OSI模型,應該采用統一的模式進行定義,這才有了Socket編程
  • 2.Socket網絡編程

    Socket(套接字),是一種對TCP/UDP 網絡協議進行的一種包裝(或者稱為協議的一種抽象應用),本身的特點提供了不同進程之間的數據通訊操作

    • TCP(傳輸控制協議)
      • 采用有狀態的通訊機制進行傳輸,在通訊時會通過三次握手機制保證與一個指定節點的數據傳輸的可靠性,在通訊完畢會通過四次揮手的機制關閉連接,由于每次數據的通訊前都需要消耗大量的時間進行連接控制,所以執行性能低,且資源占用較大
    • UDP(數據報協議 /用戶數據報協議)
      • 采用無狀態的通訊機制進行傳輸。沒有了TCP中復雜的握手與揮手處理機制,這樣就節約了大量的系統資源,同時數據傳輸性能較高,但由于不保存單個節點的連接狀態,所以發送的數據不一定可以被全部接受。
      • UDP不需要鏈接就可以直接發送數據,并且多個接受端都可以同時接受同樣的信息,所以UDP適合于廣播操作

    不論是TCP還是UDP協議,都是對傳輸層操作的保證,數據按照OSI 七層模型來說 一定要通過網絡層進行路由的配置,同時利用數據鏈路層添加數據幀,最終利用物理層發出,但是由于Socket機制的存在,所以開發者只需要編寫處理的核心代碼,而具體的傳輸,協議操作就完全被包裝了

    3.TCP通訊

    TCP是面向連接的網絡傳輸協議,在進行TCP通訊的過程中其安全性以及穩定性都是最高的,雖然性能會差些,但是對于當前網絡環境來講主要還是使用TCP協議的居多
    python中使用socket.socket類即可實現TCP程序開發:

    No函數類型描述
    1socket()構造獲取socket類對象
    2bind(hostname,port)方法在指定主機的端口綁定監聽
    3listen()方法在綁定的端口上開啟監聽
    4accept()方法等待客戶端連接,連接后返回客戶端地址
    5send(data)方法發送數據
    6recv(buffer)方法接收數據
    7close()方法關閉套接字連接
    8connect(hostname,port)方法設置連接的主機名稱與端口號
  • 客戶端開發過程:
  • 創建TCP客戶端套接字
  • 和服務端套接字建立連接
  • 發送數據給服務端
  • 接收服務端數據
  • 關閉套接字
  • 服務端開發過程
  • 創建服務端套接字對象
  • 設置端口端口號復用–讓服務端關閉后端口號立即釋放
  • 綁定端口號
  • 設置監聽
  • 等待接受客戶端連接(接收客戶端的套接字與端口)
  • 接受數據
  • 發送數據
  • 關閉套接字(關閉客戶端套接字與服務端套接字)
  • 整個Socket網絡編程之中基本的核心流程就是服務端開啟監聽端口,等待客戶端連接,而客戶端想要訪問服務器就必須進行服務器的地址連接,而后進行響應的數據的請求或響應內容的接收

    #-------------這是服務端-------- import socket #服務端的地址端口 SERVER_HOST='localhost' SERVER_PORT=8080 def main():#socket網絡服務每一次處理完成之后一定要使用close()關閉,所以使用with結構定義with socket.socket() as server_socket:#創建服務端Socketserver_socket.bind((SERVER_HOST,SERVER_PORT))#綁定服務端主機與端口server_socket.listen()#開啟監聽print('[服務端]服務端啟動完成,在%s端口上監聽等待客戶端連接。。。'%SERVER_PORT)new_socket,iport=server_socket.accept()#等待客戶端連接,處于阻塞狀態new_socket.send('你好,這里是服務端!'.encode())print(iport,'連接成功! 響應:',new_socket.recv(128).decode()) if __name__ == '__main__':main() #------------這是客戶端---------- import socket SERVER_HOST='127.0.0.1'#要連接的服務端的主機名稱或ip地址 SERVER_PORT=8080 def main():with socket.socket() as client_socket:#建立客戶端socketclient_socket.connect((SERVER_HOST,SERVER_PORT))#連接服務器print('服務端響應數據:%s'%client_socket.recv(128).decode())#接收數據長度為128字client_socket.send('你好,這里是客戶端!'.encode())#發送消息 if __name__ == '__main__':main()

    4.echo模型

    echo程序模型來源于echo命令,在操作系統內部提供一個echo命令進行內容的回顯
    echo指令 輸入什么–返回什么

    將echo的概念擴大到網絡環境中,就可以理解為客戶端輸入一組數據發送到服務端,那么服務端接受之后對該數據進行響應,這種模型就是網絡編程echo模型

    在整個網絡編程中,由于所有網絡程序一定要有一個綁定的端口號存在,所以一個端口只允許綁定一個服務,如果出現端口被占用的情況,那么程序將無法正常啟動

    對于當前服務端程序如果想要測試,簡單可以直接通過telnet命令來完成,每當用戶輸入一個內容之后就會立即將此內容發送到服務端,但window命令行采用的GBK編碼,會造成亂碼,但是可以測試服務端是正確的

    #-------------這是服務端-------- import socket #服務端的地址端口 SERVER_HOST='localhost' SERVER_PORT=8080 def main():#socket網絡服務每一次處理完成之后一定要使用close()關閉,所以使用with結構定義with socket.socket() as server_socket:#創建服務端Socketserver_socket.bind((SERVER_HOST,SERVER_PORT))#綁定服務端主機與端口server_socket.listen()#開啟監聽print('[服務端]服務端啟動完成,在%s端口上監聽等待客戶端連接。。。'%SERVER_PORT)cli_socket,iport=server_socket.accept()#等待客戶端連接,處于阻塞狀態with cli_socket:#進行客戶端的處理while True:#不斷進行信息的接收與響應data = cli_socket.recv(128).decode() # 接收客戶端傳過來的數據if data.upper()=='BYEBYE':#客戶端輸入此指令cli_socket.send('exit'.encode())break#結束循環else:#進行正常的響應cli_socket.send(('echo %s'%data).encode())#向客戶端進行去請求響應 if __name__ == '__main__':main() #------------這是客戶端---------- import socket SERVER_HOST='127.0.0.1'#要連接的服務端的主機名稱或ip地址 SERVER_PORT=8080 def main():with socket.socket() as client_socket:#建立客戶端socketclient_socket.connect((SERVER_HOST,SERVER_PORT))#連接服務器while True:#客戶端要不斷與服務端交互input_data=input('請輸入要發送的數據(輸入byebye結束):')client_socket.send(input_data.encode())#數據發送echo_data=client_socket.recv(100).decode()if echo_data.upper()=='EXIT':#結束break#斷開連接else:print(echo_data)#輸出服務端響應內容 if __name__ == '__main__':main()

    當服務器端引入并發編程的概念之后,那么就可以同時進行多個客戶端的請求處理,在開發行業內有一個“高并發”指的就是連接客戶端比較多,所以這個時候如何處理好服務端處理性能就成為項目設計的關鍵

    #-------------這是服務端-------- import multiprocessing import socket #服務端的地址端口 SERVER_HOST='localhost' SERVER_PORT=8080 def echo_handle(cli_socket,iport):#進程處理函數print('[服務端],在%s端口上監聽客戶端。。。' % iport[1])with cli_socket: # 進行客戶端的處理while True: # 不斷進行信息的接收與響應data = cli_socket.recv(128).decode() # 接收客戶端傳過來的數據if data.upper() == 'BYEBYE': # 客戶端輸入此指令cli_socket.send('exit'.encode())break # 結束循環else: # 進行正常的響應cli_socket.send(('echo %s' % data).encode()) # 向客戶端進行去請求響應 def main():#socket網絡服務每一次處理完成之后一定要使用close()關閉,所以使用with結構定義with socket.socket() as server_socket:#創建服務端Socketserver_socket.bind((SERVER_HOST,SERVER_PORT))#綁定服務端主機與端口server_socket.listen()#開啟監聽while True:#不斷接受請求print('[服務端]服務端啟動完成,在%s端口上監聽等待客戶端連接。。。' % SERVER_PORT)cli_socket, iport = server_socket.accept() # 等待客戶端連接,處于阻塞狀態process=multiprocessing.Process(target=echo_handle,args=(cli_socket,iport),name='客戶端進程-%s'%iport[1])#定義進程process.start()#啟動進程 if __name__ == '__main__':main()

    5.UDP

    UDP也是網絡傳輸層上的一種協議,但與TCP相比,UDP本身采用的是不安全的連接,所以來講每一次通過UDP發送對1數據不一定可以接收到,但是由于其性能比較好,所以未來會有廣闊的發展前景

    在Python中對于TCP/UDP本身的實現結構差別不大,都是通過socket.socket類完成的,只需要設置一些參數即可將其設為UDP(數據報協議)

    UDP與TCP服務端最大的區別是不再需要過多的考慮到數據穩定性的連接問題了,所以也不再設置有具體的監聽操作,在每次接收到請求之后只需要獲取客戶端的原始地址,直接根據原路返回即可

    #-------------這是服務端-------- import socket #服務端的地址端口 SERVER_HOST='localhost' SERVER_PORT=8080 def main():#socket網絡服務每一次處理完成之后一定要使用close()關閉,所以使用with結構定義#socket.AF_INET ip4網絡協議進行服務端創建#socket.SOCK_DGRAM創建一個數據報協議的服務端(UDP)with socket.socket(socket.AF_INET,socket.SOCK_DGRAM) as server_socket:#創建服務端Socketserver_socket.bind((SERVER_HOST,SERVER_PORT))#綁定服務端主機與端口print('[服務端]服務端啟動完成,在%s端口上監聽等待客戶端連接。。。'%SERVER_PORT)while True:#不斷進行接收data,iport=server_socket.recvfrom(30)#接收客戶端發送的數據print(iport, '連接成功! 響應:')echo_data=('echo %s'%data.decode()).encode()#響應數據 從哪來會那去server_socket.sendto(echo_data,iport)#將內容響應到發送端上if __name__ == '__main__':main() #------------這是客戶端---------- import socket SERVER_HOST='127.0.0.1'#要連接的服務端的主機名稱或ip地址 SERVER_PORT=8080 def main():with socket.socket(socket.AF_INET,socket.SOCK_DGRAM) as client_socket:#建立客戶端socketwhile True:#客戶端要不斷與服務端交互input_data=input('請輸入要發送的數據(輸入byebye結束):')client_socket.sendto(input_data.encode(),(SERVER_HOST,SERVER_PORT))#數據發送if input_data:#如果有數據echo_data=client_socket.recv(100).decode()#響應數據print('服務端響應數據: %s'%echo_data)#輸出內容else:#沒有數據 (直接回車表示程序結束)break #退出交互if __name__ == '__main__':main()

    6.UDP廣播

    使用UDP除了可以建立快速的網絡通訊之外,實際還有一個主要的功能就是實現數據廣播的操作,它可以實現一個局域網內的所有主機信息的廣播處理,要實現UDP廣播操作,則一定要在程序之中使用如下的方法進行定義:

    setsockopt(self,level:int,optname:int,value:Union[int,bytes]) #level:設置選項所在的協議層編號,有如下四個可用的配置項 #socket.SOL_SOCKET:基本套接字接口 #socket.IPPROTO_IP:IP4套接字接口 #socket.IPPROTO_IPV6:IPv6套接字接口 #socket.IPPROTO_TCP:TCP套接字接口 #optname:設置選項名稱,例如,如果要進行廣播則可以使用 socket.BROADCAST #value:設置選項的具體內容

    如果要進行廣播肯定要有廣播的接收端,而接收端不一定可以接收到廣播,但只要打開接收端就可以接收到廣播

    #------------這是廣播接收端---------- import socket BROADCAST_CLIENT_ADDR=('0.0.0.0',21567)#客戶端的綁定地址 當前主機 SERVER_HOST='127.0.0.1'#要連接的服務端的主機名稱或ip地址 SERVER_PORT=8080 def main():with socket.socket(socket.AF_INET,socket.SOCK_DGRAM) as client_socket:#建立客戶端socketclient_socket.setsockopt(socket.SOL_SOCKET,socket.SO_BROADCAST,1)#設置廣播模式client_socket.bind(BROADCAST_CLIENT_ADDR)#綁定廣播客戶端地址while True:#不斷進行接收message,iport=client_socket.recvfrom(100)#接收廣播信息print('接收的消息內容為%s,消息來源%s,消息端口%s'%(message.decode(),iport[0],iport[1]))if __name__ == '__main__':main()

    當客戶端執行后就持續等待服務端消息的發送,就跟所有手機一樣,如果手機沒有待機的狀態輪詢服務器,那么就不可能接聽電話或者短息。

    #-------------這是廣播發送端-------- import socket BROADCAST_SERVER_ADDR=('<broadcast>',21567)#設置廣播地址 def main():#socket網絡服務每一次處理完成之后一定要使用close()關閉,所以使用with結構定義#socket.AF_INET ip4網絡協議進行服務端創建#socket.SOCK_DGRAM創建一個數據報協議的服務端(UDP)with socket.socket(socket.AF_INET,socket.SOCK_DGRAM) as server_socket:#創建服務端Socketserver_socket.setsockopt(socket.SOL_SOCKET,socket.SO_BROADCAST,1)#設置廣播模式server_socket.sendto('這是廣播發送端'.encode(),BROADCAST_SERVER_ADDR) if __name__ == '__main__':main()

    在進行廣播處理的時候只需要設置一個《 broadcast》地址就可以實現廣播的處理,而對于接收端而言則不能保證信息可以正常接收

    7.HTTP

    在標準的網絡通信之中使用的是socket編程,而socket編程是對TCP/UDP協議進行抽象實現,在整個實現之中,可以清楚的發現,幾乎不需要過多的考慮TCP/UDP實現細節,而后完全基于socket就可以非常簡單的實現了

    但是socket編程本身會存在一個問題,就是必須提供兩個程序端:客戶端/服務端,服務端是整個網絡編程的核心所在,但是如果每一次服務端的升級都需要進行客戶端的強制更新,那么這種做法就會顯得非常麻煩了,所以在傳統網絡編程的基礎上就形成了HTTP協議(是針對TCP協議的一種更高級的包裝,TCP協議本身存有性能問題,所以HTTP實現也可能產生更大的性能問題,所以未來可能在UDP協議基礎上實現HTTP協議)。

    HTTP協議是一種應用在www萬維網上實現數據傳輸的一種數據交互協議。客戶端基于瀏覽器向服務器端發送HTTP服務請求,服務端會根據用戶的請求進行數據文件的加載,并將要回應的數據信息以HTML文件格式進行傳輸,當瀏覽器接收到此數據信息時就可以直接進行代碼的解析并將數據信息顯示給用戶瀏覽

    在整個的HTTP開發流程之中,最為重要的設計就放在HTML代碼的編寫上,對于WEB服務器開發者而言更為重要是清楚HTTP服務器的開發

    雖然HTTP是基于TCP協議基礎之上開發的新協議,但其本質并沒有脫離傳統的TCP協議(可靠連接,數據交互),隨后在TCP協議的基礎上擴充了HTTP自己的內容,就成為了新的協議,而這些內容實際上都是隨著每一次請求和響應的頭部信息來進行發送的

    在整個HTTP請求和響應的處理過程中,核心問題就在于:請求和響應的頭部信息有哪些,響應狀態碼(HTTP服務請求之后的狀態碼是確定響應能否正確執行的關鍵部分)

    在HTTP協議之中,為了便于用戶的請求,所以設計有多種請求模式(比較常見的就是get/post),對于一些流行的Restful設計的結構,有可能會進行這些不同模式的請求區分,隨著HTTP版本的不斷提升,請求的模式也在不斷的增加

    No方法描述
    1GET請求指定的頁面信息,并返回實體主體
    2HEAD類似于get請求,只不過返回的響應中沒有具體的內容,用于獲取請求頭部數據
    3POST向指定的資源提交數據進行處理請求(例如提交表單或上傳文件)
    4PUT從客戶端向服務器傳輸數據取代替指定文檔的內容
    5DELETE請求服務器刪除指定的頁面
    6CONNECTHTTP/1.1協議中預留給能夠將連接改為管道方式的代理服務器
    7OPTIONS允許客戶端查看服務器的性能
    8TRACE回顯服務器接收到的請求,主要用于測試或診斷

    在每一次客戶端發送HTTP請求的時候除了真實的內容之外,還會包含有許多的頭部信息

    No頭部信息描述實例
    1Accept設置客戶端顯示類型Accept: text/html,application
    2Accept-Encoding設置瀏覽器可以支持的壓縮編碼類型Accept-Encoding: gzip, deflate, br
    3Accept-Language瀏覽器可接受的語言Accept-Language: zh-CN,zh;q=0.9
    4Cookie將客戶端保存的數據發送到服務器Cookie:name=lsf
    5Content-Length請求內容的長度Content-Length:348
    6Content-Type請求與實體對應的MIME信息
    7HOST請求主機HOST:www.baidu.com
    8Referer訪問來路Referer:https://www.baidu.com.html

    服務器能否正常運行,還有一個關鍵性的問題,就是服務器端對于請求的響應編碼回應

    分類描述
    1**信息,服務器接收到請求,需要請求者繼續執行操作
    2**成功,操作被成功接收并處理
    3**重定向,需要進一步的操作以完成請求
    4**客戶端錯誤,請求包含語法錯誤或無法完成請求
    5**服務器錯誤,服務器在處理請求的過程中發送了錯誤

    在每一次HTTP服務器響應的時候實際也存在各種頭信息,這些頭信息實際上就是告訴瀏覽器該如何解釋代碼

    No頭信息描述
    1Content-Encoding返回壓縮編碼類型
    2Content-Language響應內容支持的語言
    3Content-Length響應內容的長度
    4Content-Type響應數據的MIME類型
    5Last-Modified請求資源的最后修改時間
    6Location重定向路徑
    7refersh資源定時刷新配置
    8Serverweb服務器軟件名稱
    9Set-Cookie設置Http C ookie

    8.HTTP響應

    在HTTP編程之中核心的本質依舊是進行請求和響應,只不過這個響應處理數據之外還需包含頭信息,這些內容一定要被瀏覽器進行解析,瀏覽器在進行請求的時候需要依據服務器的主機名稱和訪問端口進行請求的發送,
    所有的HTTP服務器一定要通過瀏覽器進行訪問,服務器綁定在本機的80端口上,那么就可直接進行本地服務訪問,瀏覽器輸入:http://localhost

    #---------------http基礎服務端--------- import socket #http是基于TCP協議,所以一定使用socket import multiprocessing #考慮到性能問題,為每一次請求開啟一個新的進程 class HttpServer:'''服務器的程序類'''def __init__(self,port):#服務器要有一個監聽的端口self.server_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)#創建socket實例#考慮到不同系統的問題,80端口是一個必爭端口,該端口屬于系統的核心端口,所以將核心任務與核心端口綁定self.server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)self.server_socket.bind(('0.0.0.0',port))#綁定核心端口self.server_socket.listen()#啟動監聽def start(self):'''服務器開始提供服務'''while True:#持續提供服務cli_socket,iport=self.server_socket.accept()#接收客戶端請求print('新的客戶端連接,客戶端ip:%s,客戶端端口:%s'%(iport[0],iport[1]))#輸出客戶端信息#將客戶端都設置為一個獨立的進程存在 都分別進行請求的回應handle_cli_process=multiprocessing.Process(target=self.handle_response,args=(cli_socket,))handle_cli_process.start()#進程啟動def handle_response(self,cli_socket):'''對每一個指定的客戶端進行響應'''request_headers=cli_socket.recv(1024)#用戶通過瀏覽器發送的請求本身就攜帶頭信息print('客戶端請求頭信息:%s'%request_headers.decode())#輸入用戶請求頭信息response_start_line='HTTP/1.1 200 OK'#本次的響應成功response_headers='Server: wph Server\r\nContent-Type:text/html\r\n'#可以添加更多的響應頭信息response_body= '<html>'\' <head>'\' <title>測試</title>'\' <meta charset="UTF-8"/>'\' </head>'\'<body>'\' <h1>測試頁面</h1>'\'</body>'\'</html>'response=response_start_line+response_headers+'\r\n'+response_body#最終的響應內容cli_socket.send((response).encode())#服務端響應cli_socket.close()#HTTP不保留用戶狀態,所以每次處理后都斷開連接,否則會造成性能開支,且這些開支是無意義的def main():http_server=HttpServer(80)#80為服務器的默認端口,可以不用輸入,直接輸入域名即可http_server.start()#開啟服務 if __name__ == '__main__':main()

    9.建立響應目錄

    如果html代碼以字符串的形式出現在整個Python程序里面,那么這樣的HTML代碼是很難被前端進行維護的,前端需要的是一個可以進行響應的處理目錄,相當于建立一個專屬的html響應代碼目錄,而后所有要響應的內容都要保存在此目錄之中

    #---------------http基礎服務端--------- import socket #http是基于TCP協議,所以一定使用socket import re import os #進行文件路徑的定義 #os.getcwd() 當前文件的根目錄 os.sep \ HTML_ROOT_DIR=os.getcwd()+os.sep#響應目錄 import multiprocessing #考慮到性能問題,為每一次請求開啟一個新的進程 class HttpServer:'''服務器的程序類'''def __init__(self,port):#服務器要有一個監聽的端口self.server_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)#創建socket實例#考慮到不同系統的問題,80端口是一個必爭端口,該端口屬于系統的核心端口,所以將核心任務與核心端口綁定self.server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)self.server_socket.bind(('0.0.0.0',port))#綁定核心端口self.server_socket.listen()#啟動監聽def start(self):'''服務器開始提供服務'''while True:#持續提供服務cli_socket,iport=self.server_socket.accept()#接收客戶端請求print('新的客戶端連接,客戶端ip:%s,客戶端端口:%s'%(iport[0],iport[1]))#輸出客戶端信息#將客戶端都設置為一個獨立的進程存在 都分別進行請求的回應handle_cli_process=multiprocessing.Process(target=self.handle_response,args=(cli_socket,))handle_cli_process.start()#進程啟動def handle_response(self,cli_socket):'''對每一個指定的客戶端進行響應'''request_headers=cli_socket.recv(1024)#用戶通過瀏覽器發送的請求本身就攜帶頭信息#使用正則提取請求頭信息file_name=re.match(r'\w+ +(/[^ ]*)',request_headers.decode().split('\r\n')[0]).group(1)# file_name=request_headers.decode().split(' ',2)[1]if file_name=='/':file_name= 'wenjian/index.html' #為根目錄if file_name.endswith('.wenjian') or file_name.endswith('.htm'):cli_socket.send(self.get_html_data(file_name).encode())#服務端響應else:#二進制圖表內容cli_socket.send(self.get_binary_data(file_name))#響應二進制數據cli_socket.close()#HTTP不保留用戶狀態,所以每次處理后都斷開連接,否則會造成性能開支,且這些開支是無意義的def read_file(self,file_name):#讀文件數據file_path=os.path.normpath(HTML_ROOT_DIR+file_name)#文件的完整路徑file=open(file_path,'rb')#采用二進制流的形式讀取file_data=file.read()#讀取文件內容file.close()return file_data #返回讀取的數據def get_binary_data(self,file_name):#二進制文件的讀取response_body=self.read_file(file_name)return response_bodydef get_html_data(self,file_name):#讀取指定文件response_start_line = 'HTTP/2 200 OK\r\n'# 響應頭response_headers = 'Server PWS/2.0\r\n' # 可以添加更多的響應頭信息response_body =self.read_file(file_name).decode()#設置響應內容response = response_start_line + response_headers + '\r\n' + response_body # 最終的響應內容return response def main():http_server=HttpServer(80)#80為服務器的默認端口,可以不用輸入,直接輸入域名即可http_server.start()#開啟服務 if __name__ == '__main__':main()

    10.動態請求處理

    對于web開發來說,分為兩個處理階段:靜態web處理,動態web處理,在之前設置的響應目錄實際上就是屬于靜態web處理,而動態web是可以進行動態的判斷來決定最終返回的數據內容。

    #---------------http基礎服務端--------- import socket #http是基于TCP協議,所以一定使用socket import re import os #進行文件路徑的定義 import sys #模塊加載定位 sys.path.append('page')#追加模塊加載路徑 #os.getcwd() 當前文件的根目錄 os.sep \ # HTML_ROOT_DIR=os.getcwd()+os.sep#響應目錄 # HTML_ROOT_DIR=r'F:\pythonstudy\python-Study\靜態Web服務器搭建\wenjian\static'#響應目錄 HTML_ROOT_DIR=r'F:\pythonstudy\python-Study\靜態Web服務器搭建\wenjian'#響應目錄 import multiprocessing #考慮到性能問題,為每一次請求開啟一個新的進程 class HttpServer:'''服務器的程序類'''def __init__(self,port):#服務器要有一個監聽的端口self.server_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)#創建socket實例#考慮到不同系統的問題,80端口是一個必爭端口,該端口屬于系統的核心端口,所以將核心任務與核心端口綁定self.server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)self.server_socket.bind(('0.0.0.0',port))#綁定核心端口self.server_socket.listen()#啟動監聽def start(self):'''服務器開始提供服務'''while True:#持續提供服務cli_socket,iport=self.server_socket.accept()#接收客戶端請求print('新的客戶端連接,客戶端ip:%s,客戶端端口:%s'%(iport[0],iport[1]))#輸出客戶端信息#將客戶端都設置為一個獨立的進程存在 都分別進行請求的回應handle_cli_process=multiprocessing.Process(target=self.handle_response,args=(cli_socket,))handle_cli_process.start()#進程啟動def handle_response(self,cli_socket):'''對每一個指定的客戶端進行響應'''request_headers=cli_socket.recv(1024)#用戶通過瀏覽器發送的請求本身就攜帶頭信息print(request_headers.decode())#使用正則提取請求頭信息# file_name=re.match(r'\w+ +(/[^ ]*)',request_headers.decode().split('\r\n')[0]).group(1)file_name=request_headers.decode().split(' ',2)[1]if file_name.startswith('/page'):#要訪問的是一個動態頁面request_name=file_name[file_name.index('/',1)+1:]#訪問路徑print('訪問路徑:"',request_name)param_value=""#請求參數if request_name.__contains__('?'):#參數路徑分隔符request_param=request_name[request_name.index('?')+1:]param_value=request_param.split('=')[1]#獲取參數名稱request_name=request_name[0:request_name.index('?')]#獲取模塊名稱model_name=request_name.split('/')[0]#模塊名稱method_name=request_name.split('/')[1]#函數名稱model=__import__(model_name)#加載模塊method=getattr(model,method_name)response_body=method(param_value)response_start_line = 'HTTP/2 200 OK\r\n'response_headers = 'Server PWS/2.0\r\n' # 可以添加更多的響應頭信息response = response_start_line + response_headers + '\r\n' + response_body # 最終的響應內容cli_socket.send(response.encode())cli_socket.close()#HTTP不保留用戶狀態,所以每次處理后都斷開連接,否則會造成性能開支,且這些開支是無意義的 def main():http_server=HttpServer(80)#80為服務器的默認端口,可以不用輸入,直接輸入域名即可http_server.start()#開啟服務 if __name__ == '__main__':main() #page包中echo.py文件 def service(param):#響應的處理函數if param:#如果此時的param有數據return '<h1>'+param+'</h1>'else:return '<h1>NO found</h1>' #訪問路徑:http://localhost/page/echo/service?param=

    11.urllib3

    urllib是Python中提供的一個url請求訪問的模塊,利用該模塊可以實現瀏覽器的模擬訪問,而urllib3是此模塊的升級版,主要是為Python3服務的,兩者功能類似,只不過有一些細微的差別

    #--------------urllib3-------------- import urllib3 url='http://www.baidu.com'#頁面的訪問路徑 def main():request_headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4676.0 Safari/537.36'}http=urllib3.PoolManager(num_pools=5,headers=request_headers)#獲取urllib3進程管理對象response=http.urlopen('GET',url)#發送get請求print(response.headers)#響應頭信息print(response.data.decode())#響應文件pass if __name__ == '__main__':main()

    12.twisted模塊認識

    java中的IO:

    • 傳統BIO模型–同步阻塞IO
    • 偽異步IO模型–以BIO為基礎,通過線程方式維護所有IO線程,實現相對高效的線程開銷及管理
    • NIO模型–一種同步非阻塞IO

    twisted類似NIO,是Python之中提供的專門實現異步處理的IO概念,它的主要功能是提升服務端數據的處理能力
    難道使用多進程,多線程等并發技術不能良好的解決性能問題嗎?
    要想理解twisted設計思想,那么首先就必須清楚傳統服務器端程序開發中存在的問題?

    為了讓服務端的程序更加高效的客戶端請求處理,所以引入并發編程,將每一個客戶端單獨啟動一個進程或線程,這樣就可以實現服務器的并發響應


    對于此時的開發架構已經充分的發揮出了電腦硬件性能的作用,使用硬件提供的核心支持,進行并發編程實現,但需要清楚的是早期的電腦硬件是沒有這樣所謂的多核CPU概念的,早期的設計里面使用的單核CPU,需要非常細致的解決不同進程以及線程彼此間所謂的等待與喚醒機制(死鎖問題),雖然單進程性能不高,但是卻可以有效的解決所謂的不同進程或線程之間可能產生的死鎖問題。

    如果不使用并發編程的形式,那么就不會有并發編程之中的問題(資源切換,系統調度,同步與等待所帶來的性能損耗)
    所有的傳統服務端,如果采用的是阻塞的模式,那么就會持續發生等待的操作問題,而這種等待的問題是嚴重的損耗服務端性能的,即便服務端硬件在強大,損耗也挺嚴重。

    阻塞IO本質:使用水壺燒開水,在旁邊盯著看,怕水開后,水壺燒壞
    非阻塞IO本質:不盯著水壺,對水壺進行定期的不斷輪詢,沒開就繼續干其他事,開了就結束燒水

    twisted是一個事件驅動的網絡引擎,最大特點是提供有一個事件循環處理,當外部事件發生時使用回調機制來觸發相應的處理操作,多個任務在一個線程中執行,,這種方式可以使程序盡可能的減少對于其他線程的依賴,也使得程序開發人員不在關注線程安全問題

    twsited中所有處理事件(注冊,注銷,運行,回調處理等)全部交由reactor進行統一管理,在整個程序運行過程中,reactor循環會以單線程的模式持續運行,當需要執行回調處理時reactor會暫停循環,當回調操作執行完畢后將繼續采用循環的形式進行其他任務處理,由于這種操作是從平臺行為中抽象出來的,這樣就使得網絡協議棧的任何位置很容易的進行事件響應

    13.twisted開發TCP程序

    使用twisted最大的特點是進行服務端程序的開發,這樣的開發會為服務端的資源利用帶來極大的便利
    使用twisted實現echo程序
    如果要實現echo服務端程序的開發,那么讓服務端的處理類繼承一個twisted.internet.protocol.Protocol 父類,隨后就根據自己的需要來選擇要復寫的方法

    #-------twisted服務端程序---------- import twisted #pip install Twisted import twisted.internet.protocol import twisted.internet.reactor SERVER_PORT=8080#設置監聽端口 class Server(twisted.internet.protocol.Protocol):#服務端一定要設置一個繼承父類def connectionMade(self):#客戶端連接時觸發print('客戶端地址:%s'%self.transport.getPeer().host)def dataReceived(self,data):#接收客戶端數據print('服務端接受到的數據%s'%data.decode())#輸出接收到的數據self.transport.write(('echo %s'%data.decode()).encode())#回應 class DefaultServerFactory(twisted.internet.protocol.Factory):#定義處理工廠類protocol=Server#注冊回調操作 def main():twisted.internet.reactor.listenTCP(SERVER_PORT,DefaultServerFactory())#服務監聽print('服務啟動完畢,等待客戶端連接。。。')twisted.internet.reactor.run()#事件輪詢 if __name__ == '__main__':main()

    處理流程:定義事件的處理回調操作程序–工廠中注冊–Reactor依據工廠來獲得相應的事件回調處理操作類

    #---------------twisted客戶端---------- import twisted import twisted.internet.protocol import twisted.internet.reactor SERVER_HOST='localhost'#服務主機 SERVER_PORT=8080#連接端口 class Client(twisted.internet.protocol.Protocol):#定義用戶端處理類def connectionMade(self):print('服務器連接成功,可以進行數據交互,若要結束,則直接回車,,')self.send()#建立連接后就進行數據的發送def dataReceived(self,data):#接收服務端的數據print('服務端 接收到數據:%s'%data.decode())#輸出接收到的數據self.send()#繼續發送def send(self):#數據發送 自定義的方法input_data=input('請輸入要發送的數據:')if input_data:#如果有數據self.transport.write(input_data.encode())else:#沒有輸入內容,表示操作的結束self.transport.loseConnection()#關閉連接 class DefaultClientFactory(twisted.internet.protocol.ClientFactory):#客戶端工廠protocol=Client#定義回調clientConnectionLost=clientConnectionFailed=lambda self,connector,reason:twisted.internet.reactor.stop()#停止循環 def main():twisted.internet.reactor.connectTCP(SERVER_HOST,SERVER_PORT,DefaultClientFactory())#連接主機服務twisted.internet.reactor.run()#程序運行 if __name__ == '__main__':main()

    通過程序執行結果可以發現,此處避免了非常繁瑣的并發控制的操作,沒有了多進程或多線程的操作控制部分,整個執行流程都是基于單線程的運行模式完成(Python中的多線程存在GIL全局鎖問題,這就解決了此類問題)

    14.使用twisted開發UDP程序

    TCP是面向連接的可靠的網絡服務,所以不管使用的是socket還是twisted都需要進行連接的操作控制,這樣一定會造成不必要的性能開支,所以twisted內部也支持有UDP程序開發,因為UDP不需要保證可靠連接,所以只需要定義好用戶的處理回調操作即可。

    #----------UDP twisted服務端------- import twisted import twisted.internet.protocol import twisted.internet.reactor SERVER_PORT=8080 class EchoServer(twisted.internet.protocol.DatagramProtocol):#數據報協議def datagramReceived(self,datagram,addr):#接收數據處理print('服務端 接收到消息,消息來源IP:%s,來源端口:%s'% addr)print('服務端 接收到數據消息:%s'%datagram.decode())echo_data='echo %s'%datagram.decode()#設置回應信息self.transport.write(echo_data.encode(),addr)#將信息返回給指定客戶端 def main():twisted.internet.reactor.listenUDP(SERVER_PORT,EchoServer())#服務監聽print('服務器啟動完成,等待客戶端連接。。。')twisted.internet.reactor.run()#事件循環 if __name__ == '__main__':main()

    使用UDP進行處理的時候不在需要使用那些連接的控制,同時也不在需要通過工廠才可以與Reactor進行銜接,從結構上更加的簡單了

    #------------UDP twisted客戶端操作--------- import twisted import twisted.internet.reactor import twisted.internet.protocol SERVER_HOST='127.0.0.1' SERVER_PORT=8080 CLIENT_PORT=0#客戶端地址 class EchoClient(twisted.internet.protocol.DatagramProtocol):#UDP客戶端1def startProtocol(self):#連接的回調self.transport.connect(SERVER_HOST,SERVER_PORT)#連接print('服務器連接成功,可以進行數據交互,如果要結束會話,直接回車')self.send()#消息發送def datagramReceived(self,datagram,addr):#接收數據處理print(datagram.decode())self.send()#下一次數據發送def send(self):#數據發送 自定義方法input_data=input('請輸入要發送的信息:')if input_data:self.transport.write(input_data.encode())else:twisted.internet.reactor.stop()#停止輪詢 def main():twisted.internet.reactor.listenUDP(CLIENT_PORT,EchoClient())#服務監聽twisted.internet.reactor.run()#開啟事件循環 if __name__ == '__main__':main()

    所有網絡程序進行開發的過程中實際上只有一個核心的目的:提升服務端的資源的可用性(發揮出最大的性能),減少操作的延遲,但是,UDP當今的應用都是在即時消息通訊操作上,而對于TCP的開發操作依然是主流

    15.Deferred

    在網絡開發之中,對于服務端性能提升可以使用twisted直接完成,但是在一些客戶端與網絡服務器端交互的過程之中,有可能下載需要下載一些比較龐大的文件內容(圖片,視頻等等),按照傳統的客戶端的開發模型來講,此時就需要持續進行下載,而對于當前的客戶端也將進入到一個阻塞的開發狀態,那么在這樣的情況下為了解決客戶端的阻塞問題,就提供了Deferred的概念

    在twisted設計之中最大的特點就是持續的強調采用非阻塞的形式來完成,同時盡可能的減少并發操作,通過事件輪詢的方式來提升程序的可用資源,基于事件輪詢的機制設計出一套Deferred的模型

    #------------defered模擬-------- import twisted import twisted.internet.reactor import twisted.internet.defer import time class DeferHandle:#設置一個回調處理類def __init__(self):self.defer=twisted.internet.defer.Deferred()#獲取defer對象def get_defer(self):#讓外部獲得實例對象return self.deferdef work(self):#模擬網絡下載print('模擬網絡下載延時操作,等待3秒。。。')time.sleep(3)self.defer.callback('finish')#執行回調def handle_success(self,result):print('處理完成,進行參數的接收:%s'%result)#處理完畢后的信息輸出def handle_error(self,exp):#錯誤回調print('程序出錯:%s'%exp) def stop():twisted.internet.reactor.stop()print('服務調用結束~~~~') def main():defer_client=DeferHandle()#獲得當前的回調操作twisted.internet.reactor.callWhenRunning(defer_client.work)#執行耗時操作defer_client.get_defer().addCallback(defer_client.handle_success)#設置回調處理 執行完畢后的回調defer_client.get_defer().addErrback(defer_client.handle_error)#錯誤輸出時的回調twisted.internet.reactor.callLater(5,stop)#5秒后停止Reactor調用twisted.internet.reactor.run()#啟用事件的循環 if __name__ == '__main__':main()

    在整個程序執行完畢后,就可以直接利用所設置的calback()操作進行操作完成后的調用,基于這樣的操作模型就減少了并發編程的使用,但使用twisted程序都是在解決網絡通訊的性能問題,那么最佳的做法肯定就是Defered應用在網絡的開發環境中。
    通過Deffer模型實現TCP的echo客戶端

    #----------defer TCP 客戶端------- import twisted import twisted.internet.defer import twisted.internet.protocol import twisted.internet.reactor import twisted.internet.threads#自己控制的線程 import time SERVER_HOST='localhost' SERVER_PORT=8080 class DeferClient(twisted.internet.protocol.Protocol):#回調處理類def connectionMade(self):#創建連接print('服務器連接成功,可以進行通信,如果要結束會話,直接回車即可')self.send()#信息發送def dataReceived(self,data):#接收服務端發送的數據content=data.decode()#接收服務端發送的數據twisted.internet.threads.deferToThread(self.handle_request,content).addCallback(self.handle_success)def handle_request(self,content):#數據處理過程print('客戶端 對服務端的數據 %s 進行處理,可能會產生1~2秒延遲。。。'%content)time.sleep(1)return content #返回處理結果def handle_success(self,result):#操作處理完畢print('處理完成,進行參數的接收:%s'%result)self.send()#下一的數據發送def send(self):#數據發送 自定義方法input_data=input('請輸入要發送的信息:')if input_data:self.transport.write(input_data.encode())else:self.transport.loseConnection()#關閉連接 class DefaultClientFactory(twisted.internet.protocol.ClientFactory):#客戶端工廠protocol=DeferClient#設置回調處理clientConnectionLost=clientConnectionFailed=lambda self,connector,reason:twisted.internet.reactor.stop() def main():twisted.internet.reactor.connectTCP(SERVER_HOST,SERVER_PORT,DefaultClientFactory())#服務監聽twisted.internet.reactor.run()#程序運行 if __name__ == '__main__':main()

    這種交互的模型主要是Deferred優化了客戶端之中的處理結構,在實際開發中,一個服務端有可能繼續調用其他的服務器端,而這個服務器還有可能同時要處理用戶的請求



    • 無智亦無得,以無所得故

    總結

    以上是生活随笔為你收集整理的网络编程补充的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 精品自拍视频在线观看 | 熟女一区二区三区视频 | 国产精品第5页 | 免费黄色链接 | 美女福利视频在线 | 国产精品视频1区 | 久久久久久免费毛片精品 | 免费黄毛片 | 国产精品久久久999 www日本高清视频 | 日本大奶子视频 | 诱人的乳峰奶水hd | 就要日就要操 | 亚洲国产精彩中文乱码av | 黑人100部av解禁片 | 日本黄视频在线观看 | 午夜小视频免费 | 亚洲色图国产精品 | 国产做爰视频免费播放 | 桃色在线观看 | 在线欧美国产 | 日本一二三视频 | 黄色avav| 亚洲国产精品成人综合在线 | 精品人妻久久久久久888不卡 | 制服丝袜中文字幕在线 | 一级成人免费视频 | 依依成人在线 | 人妖一区二区三区 | 中文字幕88页| 在线视频观看 | 国产精品天美传媒 | 91亚洲精品国偷拍 | 香蕉久久一区二区三区 | 亚洲国产综合视频 | 在线不卡av电影 | 天堂网wwww| 成人一级在线 | 久久美利坚 | 亚洲一区二区三区三州 | 大尺度做爰无遮挡露器官 | 欧美人妻一区二区三区 | 中国在线观看片免费 | 一级黄色片毛片 | 亚洲一区二区三区影院 | 成人一区二区三区在线 | 久久综合91| 中文字幕一区二区三区精华液 | 精品乱码一区内射人妻无码 | 日本在线小视频 | 欧美午夜精品久久久久久人妖 | 美女毛片在线 | 亚洲精品国产精品乱码不99 | av资源部| 999免费视频| 中文在线观看av | 操碰在线观看 | 亚洲国产aⅴ成人精品无吗 日韩乱论 | av网站在线观看不卡 | 久久久久不卡 | 中文字幕88页 | 国产精品麻豆成人av电影艾秋 | 日韩中文第一页 | 麻豆视频在线免费看 | 给我免费观看片在线电影的 | 麻豆传媒一区二区三区 | 日韩欧美精品久久 | 精品动漫一区二区 | 激情777 | 国产成人无码av | 丰满少妇中文字幕 | 男人舔女人下部高潮全视频 | 69视频在线观看免费 | 最新中文字幕在线播放 | 欧美在线网 | 亚洲一区二区不卡在线观看 | 国产日产欧美一区二区三区 | 在线观看日韩精品 | 亚洲黄色三级 | 久久av免费看| 日韩另类视频 | 精品三级av | 欧美在线性视频 | 国产精品jizz在线观看无码 | 成年人免费毛片 | 亚洲17p| 国产三级在线免费观看 | 久久精品99久久久 | 在线资源站 | 免费看h网站 | 97碰碰碰 | 免费久草视频 | 亚洲最大在线观看 | 欧洲中文字幕日韩精品成人 | 乱xxxxx普通话对白 | 色婷婷av国产精品 | 久久精品国产一区二区电影 | 在线精品视频一区 | 亚洲欧美激情另类 | 狠狠爱综合 |