TCP/IP
計算機與網絡設備兩情侶要談戀愛,相互通信,那么雙方就必須有規則。基于相同的方法,不同的硬件、操作系統之間的通信,都需要一種規則。而我們就把這種規則稱為協議(protocol)。
TCP/IP 是互聯網相關各類協議族的總稱。TCP/IP是指TCP和IP這兩種協議。TCP/IP是在IP協議的通信過程中,使用到的協議族的統稱。
TCP/IP協議族按層次分別為 應用層,傳輸層,網絡層,數據鏈路層,物理層。可以按照不同的模型分4層或者是7層。
將TCP/IP分為5層,越靠下越接近硬件。
應用層:應用程序收到傳輸層的數據后,接下來就是要進行解讀,解讀必須要先規定好格式,而應用層就是規定應用程序的數據格式,主要協議有HTTP等。
傳輸層:該層為兩臺主機上的應用程序提供端到端的通信,傳輸層有兩個傳輸協議為TCP(傳輸控制協議)和UDP(用戶數據報協議),TCP是一個可靠的面向連接的協議,UDP是不可靠或者說無連接的協議。
網絡層:決定如何將數據從發送方到接收方,是建立主機到主機的通信。
數據鏈路層:控制網絡層與物理層之間的通信,主要功能是保證物理線路上進行可靠的數據傳遞。
物理層:該層負責物理傳輸,與鏈路有關,也與傳輸的介質有關。
客戶端和服務器具體的
HTTP
圖片出自《圖解HTTP》書籍
三次握手,四次揮手
TCP三次握手,四次揮手,Runsen也不會怎么說,就把網上最通俗的圖放在下面 了,還是別看我很牛逼,牛逼的是做圖的大佬。
三次握手
四次揮手
圖片出自公眾號(程序員小小溪),更多的名詞和概念查找參考公眾號程序員小小溪的文章~[1]
Socket
網絡編程有一個重要的概念 socket(套接字),應用程序可以通過它發送或接收數據,套接字允許應用程序將 I/O 插入到網絡中,并與網絡中的其他應用程序進行通信。
我是來偷窺Python中的網絡通信Socket,不小心偷窺到了一個非常不錯的Socket好圖
將上面的圖片整理步驟
1.建立連接:
服務器:socket--->address--->bind--->listen--->accept
客戶端:socket--->connect
2.通信:收一發:recv(1024)
3.關閉連接:close()
實現簡單的通訊程序
服務端,server.py
#導入socket模塊
import?socket
#創建套接字?或使用server?=?socket.socket()
server?=?socket.socket(socket.AF_INET,?socket.SOCK_STREAM)
#定義綁定的ip和端口,用元組定義
ip_port?=?('127.0.0.1',?8888)
#綁定監聽:bind(address),在AF_INET下,以元組(ip,port)的形式表示地址
server.bind(ip_port)
#設置最大連接數,默認為1
server.listen(5)
#不斷接受連接:one?byone
while?True:
print("等待數據連接中……")
#接受客服端數據請求
conn,?address?=?server.accept()
'''
向客服端返回信息
(注意:python3.x以上,網絡數據的發送接收都是byte類型,
發送接收String類型數據時需要對數據進行編碼(發送:messages.enconde();接收后轉為String類型:messages.deconde()),pyhon2.x則直接發送數據無須編碼)
'''
messages?=?"連接成功!"
conn.send(messages.encode())
#計數信息條數
count=?0
#一個連接中,不斷的接受客戶端發來的數據
while?True:
data?=?conn.recv(1024)
#打印客戶端發來的數據信息
print(data.decode())
#判斷是否退出當前連接,等在下一個連接
if?data?==?b'exit':
break
#處理客戶端數據(如:響應請求等)
count=count+?1
string?=?"第"+?str(count)?+"條信息:"+?data.decode()
conn.send(string.encode())
#主動關閉連接
conn.close()
客戶端,client.py
import?socket
#創建套接字
client?=?socket.socket()
#訪問的服務器的ip和端口,用元組定義
ip_port?=?("127.0.0.1",?8888)
#連接服務器主機
client.connect(ip_port)
#同一鏈接中,不斷向服務器發生數據或請求
while?True:
#接收服務器發送或響應的數據
data?=?client.recv(1024)
#打印接收的數據;python3.x以上數據要編碼(發送:data.enconde();接收后轉為String類型:data.deconde())
print(data.decode())
messages?=?input("請輸入發生或請求的數據(exit退出):")
client.send(messages.encode())
if?messages?==?'exit':
break
'''
#接收服務器發送或響應的數據
data?=?client.recv(1024)
#打印接收的數據;python3.x以上數據要編碼,發送enconde();接收deconde()
print(data.decode())
'''
#關閉連接
client.close()
具體效果如下圖所示。
多線程通信TCP服務器與多個TCP客戶端同時進行連續通信,只需要通過threading創建多線程任務handle_client就可以了。
import?socket
import?threading
import?random
def?handle_client():
#?接受客戶端請求鏈接
client,?address?=?server.accept()
print("[*]?Accept?connection?from:?%s:%d"%?(address[0],?address[1]))
messages?=?"Hello?World!"
client.send(messages.encode())
#?連續與當前連接的客戶端通信
while?True:
#?接受客戶端數據
request?=?(client.recv(1024)).decode()
#?判斷是否結束通信
if?request?==?'exit':
break
print("[*]?Received?from?%s:%d?:?%s"%?(address[0],?address[1],?request))
#?發送響應信息給客戶端
client.send((str(random.randint(1,?1000))?+?":"+"ACK!").encode())
#?關閉當前連接
client.close()
if?__name__?==?"__main__":
#?創建套接字
server?=?socket.socket(socket.AF_INET,?socket.SOCK_STREAM)
#?定義綁定ip和端口
ip?=?'127.0.0.1'
port?=?8888
#?綁定監聽
server.bind((ip,?port))
#?設置最大連接數,默認為1
server.listen(5)
print("[*]?Listening?on?%s:%d"%?(ip,?port))
#?循環開啟線程,接受多個客戶端的鏈接通信
while?True:
#?創建一個線程
client_handler?=?threading.Thread(target=handle_client)
#?開啟線程
client_handler.start()
python3.x以上,網絡數據messages的發送接收都是byte類型,若要發送接收String類型數據時需要通過messages.enconde()對數據進行編碼,接收后通過messages.deconde()轉為String類型。pyhon2.x則直接發送數據無須編碼。
本文已收錄 GitHub,傳送門~[2] ,里面更有大廠面試完整考點,歡迎 Star。
Reference
[1] 參考公眾號程序員小小溪的文章:
https://mp.weixin.qq.com/s/KK1dnNoHrbjMyuhQptaBAQ
[2] 傳送門~:
https://github.com/MaoliRUNsen/runsenlearnpy100