1、網絡基礎編程
在學習網絡編程前,要對網絡通訊的五層協議有所瞭解,那什麼是協議呢,協議就是各方規定遵照的一種標準。緩存
網絡通訊就像寄信件,是信息與數據的交換,而在生活中咱們寄信件,信件也不是從咱們手裏瞬間到收件人手裏,每一次信件通訊,都會經歷這樣幾個固定流程:寫信、裝信封、投到郵箱、郵局取件、運輸到目的地郵局、目的地郵局根據詳細地址派送、收件人收件、拆信封、讀信。服務器
網絡通訊也是一樣的道理,數據的傳輸總有必定的流程:發送端程序將數據打包,給數據包印上目標地址,將數據包交給網關,經過路由轉發到達目的網絡,目的網絡網關在根據詳細地址分發、目的主機接收數據、拆包、讀數據。網絡
這中間咱們按照每部分負責的任務的不一樣,將整個通訊劃分爲五層(分法不惟一,這是最易理解的一種),由下到上分別是物理層、數據鏈路層、網絡層、運輸層、應用層,每一層都將較下的一層徹底封裝,消除通訊雙方軟硬件的差異,而每一層又有約定好的規則以和對方通訊,咱們這篇文章所要講的,就是發生在運輸層的通訊。socket
咱們先來思考一個問題:一臺主機的一個進程發送數據時,是如何標識它是發送給目標主機的哪一個進程呢?目標主機接受到數據時,由如何判斷這份數據是發送給本機的哪一個進程呢?tcp
這就是運輸層的任務,也就是說,運輸層負責兩個主機中的應用進程之間的通訊。那麼上面的問題究竟是怎麼解決的呢?這就要提到一個新的概念:套接字。學習
套接字的概念很簡單,每臺主機有一個惟一的主機地址標識,同時主機內還有標識本身進程的序號id,稱做端口,將這兩個標識符結合就構成了一個套接字(socket),這個套接字能惟一標識網絡中的一個進程。接下來咱們的網絡編程,都是圍繞這個套接字展開的。spa
運輸層的協議主要有UDP和TCP協議,這兩個協議都是爲了解決進程通訊,它們的區別主要是這幾點:UDP是無鏈接、不可靠協議,TCP是有鏈接、可靠協議,鏈接指的是通訊前要創建鏈接(鏈接提供了許多功能:確認、流量控制、鏈接管理等),可靠指的是若是數據未抵達有對應處理(不可靠則指只負責發送數據)。code
這樣就瞭解的差很少了,固然,關於運輸層的技術還有不少,難點重點都沒有提到,有興趣的同窗能夠本身再學習。orm
2、通訊模式
對咱們來講,進行網絡通訊的目的是爲了獲取信息,而互聯網上的信息需求者遠遠多於信息提供者,不止如此,信息的提供者必須24小時當即回覆需求者的請求,這樣就產生了客戶服務器模式。客戶服務器模式是一個邏輯概念,它將主機分爲兩類,等待請求的是服務器端、發起請求的是客戶端,因此服務器端的套接字是必須是公開的,客戶端的套接字能夠在請求時給服務器端。
3、實現
對UDP來講:由於不須要創建鏈接,因此只須要在兩臺主機上各構造一個socket,就能直接發送和接收數據了。
對TCP來講:首先須要創建鏈接,一個鏈接就是一對手動綁定的socket,鏈接成功後就能收發數據了。
結合客戶服務端模式,對同一種協議,socket的構造方法也按客戶端和服務器分爲兩種。
話很少說,上代碼!
這是基於TCP協議的:
#socket_server_tcp # import socket from socket import * ip_port=('127.0.0.1',8080) back_log=5 buffer_size=1024 tcp_server=socket(AF_INET,SOCK_STREAM) tcp_server.bind(ip_port) tcp_server.listen(back_log) while True: print('服務端開始運行了') conn,addr=tcp_server.accept() #服務端阻塞 print('雙向連接是',conn) print('客戶端地址',addr) while True: try: data=conn.recv(buffer_size) print('客戶端發來的消息是',data.decode('utf-8')) conn.send(data.upper()) except Exception: break conn.close() tcp_server.close()
#socket_client_tcp # import socket from socket import * ip_port=('127.0.0.1',8080) back_log=5 buffer_size=1024 tcp_client=socket(AF_INET,SOCK_STREAM) tcp_client.connect(ip_port) while True: msg=input('>>: ').strip() if not msg:continue tcp_client.send(msg.encode('utf-8')) print('客戶端已經發送消息') data=tcp_client.recv(buffer_size) print('收到服務端發來的消息',data.decode('utf-8')) tcp_client.close()
接下來是基於UDP協議的:
# socket_server_udp from socket import * ip_port=('127.0.0.1',8080) buffer_size=1024 udp_server=socket(AF_INET,SOCK_DGRAM) #數據報 udp_server.bind(ip_port) while True: data,addr=udp_server.recvfrom(buffer_size) print('收到來自{}的消息:{}'.format(addr, data)) udp_server.sendto(data.upper(),addr)
# socket_client_udp from socket import * ip_port=('127.0.0.1',8080) buffer_size=1024 udp_client=socket(AF_INET,SOCK_DGRAM) #數據報 while True: msg=input('>>: ').strip() udp_client.sendto(msg.encode('utf-8'),ip_port) data,addr=udp_client.recvfrom(buffer_size) # print(data.decode('utf-8')) print('收到服務端發來的消息', data)
運行下試試!
這兩對代碼已經能實現基本的功能,但還有許多功能沒有實現,如TCP版不能同時鏈接多用戶,粘包問題(一次接收的數據若是大於緩存區大小就會把剩下的內容附加到下次接受的開頭),這些咱們放到下次來說。