1.先說下subprocess模塊的用法,為了舉個黏包的例子
# 通過一個例子 來認識網絡編程中的一個重要的概念 # 所有的客戶端執行server端下發的指令,執行完畢后,客戶端將執行結果給返回給服務端 import subprocess # 這個模塊其實並不好用,這里為了舉例子。調用操作系統的命令模塊 res = subprocess.Popen('dir', shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) # 執行dir命令,並將標准輸出和錯誤內容裝到了管道中 print('stdout : ', res.stdout.read().decode('gbk')) # 從管道中獲取控制台的內容,windows控制台執行完畢后,得到的是bytes類型的,需要解碼成gbk才可不亂碼顯示,windows控制台返回的是gbk的,所以這里要gbk解碼 print('stderror: ', res.stderr.read().decode('gbk'))
2.寫一個tcp的server端和client,模擬黏包的現象,tcp端發送windows的命令給client,client接收后執行該命令后,將控制台返回的內容傳輸到server端
tcpserver.py
# 通過一個例子 來認識網絡編程中的一個重要的概念 # 所有的客戶端執行server端下發的指令,執行完畢后,客戶端將執行結果給返回給服務端 # 基於tcp實現遠程執行命令 # 在server下發windows操作系統命令給client,client執行完畢后返回給sercer # 出現了黏包現象 # 數據亂了,數據沒有接收完,下次接收接收到了未接收到的數據等現象 # tcp不會丟包,會黏包。 # 當傳輸的包很大的時候,tcp協議會將其拆分開進行傳輸。 import socket sk = socket.socket() sk.bind(('127.0.0.1', 8080)) sk.listen() conn, addr = sk.accept() while True: cmd = input('輸入想要客戶端windows系統想要執行的命令:') conn.send(cmd.encode('utf-8')) msg = conn.recv(1024).decode('utf-8') print(msg) conn.close() sk.close()
tcpclient.py
# client接收服務端命令 import socket import subprocess sk = socket.socket() sk.connect(('127.0.0.1', 8080)) while True: cmd = sk.recv(1024).decode('utf-8') res = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout = 'stdout : ' + res.stdout.read().decode('gbk') stderr = 'stderr : ' + res.stderr.read().decode('gbk') #print(stdout) #print(stderr) # res.stdout.read() 為cmd命令執行后返回的結果,返回的是bytes類型數據 sk.send(stdout.encode('utf-8')) sk.send(stderr.encode('utf-8')) sk.close()
3.udp不黏包,但會丟包例子,與上類似
udpserver.py
# 測試結果,udp不會黏包,但udp會丟包,數據發送出去后,一旦另一端接收的緩存不夠大,而發送的數據很大時,未接收的數據,會丟棄掉。同時udp大了緩存限制會丟棄包 import socket sk = socket.socket(type=socket.SOCK_DGRAM) #sk.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) # 避免服務重啟的時候報address already in use。加上這個解決 sk.bind(('127.0.0.1', 8081)) msg, addr = sk.recvfrom(1024) while True: cmd = input('輸入想要客戶端windows系統想要執行的命令:') if cmd == 'q': break sk.sendto(cmd.encode('utf-8'), addr) msg, addr = sk.recvfrom(1024) print(msg.decode('utf-8')) sk.close()
udpclient.py
# client接收服務端命令 import socket import subprocess sk = socket.socket(type=socket.SOCK_DGRAM) ip_port = ('127.0.0.1', 8081) sk.sendto(b'hello', ip_port) while True: cmd, addr= sk.recvfrom(1024) res = subprocess.Popen(cmd.decode('utf-8'), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout = 'stdout : ' + res.stdout.read().decode('gbk') stderr = 'stderr : ' + res.stderr.read().decode('gbk') #print(stdout) #print(stderr) # res.stdout.read() 為cmd命令執行后返回的結果,返回的是bytes類型數據 sk.sendto(stdout.encode('utf-8'), ip_port) sk.sendto(stderr.encode('utf-8'), ip_port) sk.close()
4.tcp為什么會黏包
黏包是這樣出現的
tcp的拆包機制是類似這樣的
5.udp為什么不會黏包