標籤:win 現象 執行 src 輸入 訊息 hid RoCE connect
粘包現象
讓我們基於tcp先製作一個遠程執行命令的程式(1:執行錯誤命令 2:執行ls 3:執行ifconfig)
注意注意注意:
res = subprocess.Popen(cmd.decode(‘utf-8‘),
shell = True,
stderr = subprocess.PIPE,
stdout = subprocess.PIPE)
的結果的編碼是以當前所在的系統為準的,如果是windows,那麼res.stdout.read()讀出的就是GBK編碼的,在接收端需要用GBK解碼
且只能從管道裡讀一次結果
注意:命令ls -l ; lllllll ; pwd 的結果是既有正確stdout結果,又有錯誤stderr結果
#!/usr/bin/python3#_*_coding:utf-8_*_#__author__ = ‘Tengbibo‘import socketimport subprocessip_port = (‘127.0.0.1‘,6969)BUFSIZE = 1024tcp_socket_server = socket.socket()tcp_socket_server.bind(ip_port)tcp_socket_server.listen(5)while True: conn,addr = tcp_socket_server.accept() print(‘connect from:‘,addr) while True: cmd = conn.recv(BUFSIZE) if len(cmd) == 0:break res = subprocess.Popen(cmd.decode(‘utf-8‘),shell = True, stdout = subprocess.PIPE, stdin = subprocess.PIPE, stderr = subprocess.PIPE) stderr = res.stderr.read() stdout = res.stdout.read() conn.send(stderr) conn.send(stdout)
服務端
#!/usr/bin/python3#_*_coding:utf-8_*_#__author__ = ‘Tengbibo‘import socketBUFSIZE=1024ip_port=(‘127.0.0.1‘,6969)client = socket.socket()client.connect(ip_port)while True: cmd = input(‘>>: ‘).strip() if len(cmd) == 0:continue if cmd == ‘quit‘:break client.send(cmd.encode(‘utf-8‘)) act_res=client.recv(BUFSIZE) print(act_res.decode(‘utf-8‘),end=‘‘)
用戶端
上述程式是基於tcp的socket,在運行時會發生粘包
什麼是粘包
須知:只有TCP有粘包現象,UDP永遠不會粘包。
首先需要掌握一個socket收發訊息的原理
發送端可以是一K一K地發送資料,而接收端的應用程式可以兩K兩K地提走資料,當然也有可能一次提走3K或6K資料,或者一次只提走幾個位元組的資料,也就是說,應用程式所看到的資料是一個整體,或說是一個流(stream),一條訊息有多少位元組對應用程式是不可見的,因此TCP協議是面向流的協議,這也是容易出現粘包問題的原因。而UDP是面向訊息的協議,每個UDP段都是一條訊息,應用程式必須以訊息為單位提取資料,不能一次提取任意位元組的資料,這一點和TCP是很不同的。怎樣定義訊息呢?可以認為對方一次性write/send的資料為一個訊息,需要明白的是當對方send一條資訊的時候,無論底層怎樣分段分區,TCP協議層會把構成整條訊息的資料區段排序完成後才呈現在核心緩衝區。
例如基於tcp的通訊端用戶端往服務端上傳檔案,發送時檔案內容是按照一段一段的位元組流發送的,在接收方看了,根本不知道該檔案的位元組流從何處開始,在何處結束
所謂粘包問題主要還是因為接收方不知道訊息之間的界限,不知道一次性提取多少位元組的資料所造成的。
此外,發送方引起的粘包是由TCP協議本身造成的,TCP為提高傳輸效率,發送方往往要收集到足夠多的資料後才發送一個TCP段。若連續幾次需要send的資料都很少,通常TCP會根據最佳化演算法把這些資料合成一個TCP段後一次發送出去,這樣接收方就收到了粘包資料。
- TCP(transport control protocol,傳輸控制通訊協定)是連線導向的,面向流的,提供高可靠性服務。收發兩端(用戶端和伺服器端)都要有一一成對的socket,因此,發送端為了將多個發往接收端的包,更有效發到對方,使用了最佳化方法(Nagle演算法),將多次間隔較小且資料量小的資料,合并成一個大的資料區塊,然後進行封包。這樣,接收端,就難於分辨出來了,必須提供科學的拆包機制。 即面向流的通訊是無訊息保護邊界的。
- UDP(user datagram protocol,使用者資料包通訊協定)是不需連線的,面向訊息的,提供高效率服務。不會使用塊的合并最佳化演算法,, 由於UDP支援的是一對多的模式,所以接收端的skbuff(通訊端緩衝區)採用了鏈式結構來記錄每一個到達的UDP包,在每個UDP包中就有了訊息頭(訊息來源地址,連接埠等資訊),這樣,對於接收端來說,就容易進行區分處理了。 即面向訊息的通訊是有訊息保護邊界的。
- tcp是基於資料流的,於是收發的訊息不可為空,這就需要在用戶端和服務端都添加空訊息的處理機制,防止程式卡住,而udp是基於資料報的,即便是你輸入的是空內容(直接斷行符號),那也不是空訊息,udp協議會幫你封裝上訊息頭,實驗略
udp的recvfrom是阻塞的,一個recvfrom(x)必須對唯一一個sendinto(y),收完了x個位元組的資料就算完成,若是y>x資料就丟失,這意味著udp根本不會粘包,但是會丟資料,不可靠
tcp的協議資料不會丟,沒有收完包,下次接收,會繼續上次繼續接收,己端總是在收到ack時才會清除緩衝區內容。資料是可靠的,但是會粘包。
Python基礎之-socket編程