Python-網絡編程之粘包、UDP

粘包問題

什麼是粘包問題呢?shell

在咱們寫 tcp socket編程的時候,tcp協議是一個流式的協議,服務端第一次發送的數據,客戶端沒法準確一次性的接收完畢,下一次發送的數據與上一次數據粘在一塊兒。編程

即:sass

一、 沒法預測對方須要接收的數據大小長度安全

二、 屢次連續發送數據量小的,而且時間間隔短的數據 會一次性打包一塊兒發送服務器

TCP 協議的特性:socket

​ 會將屢次連續發送的數據量小的,而且時間間隔短的數據一次性發送完畢tcp

subprocess模塊

咱們用subprocess 模塊來演示一個粘包問題。code

# 服務端
# coding=utf-8
import socket
import subprocess

server = socket.socket()
address = ("127.0.0.1",8888)
server.bind(address)
server.listen(5)

while True:
    conn , addr = server.accept()
    while True:
        try:
            cmd = conn.recv(1024).decode("utf-8")
            print(cmd)

            if cmd == "q":
                break

            obj = subprocess.Popen(
                cmd,shell=True,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE
            )

            res = obj.stdout.read() + obj.stderr.read()
            conn.send(res)
        except Exception:
            break
    conn.close()
# 客戶端
# coding=utf-8

import socket
client = socket.socket()
address = ("127.0.0.1",8888)
client.connect(address)

while True:
    cmd = input("請輸入>>>")
    client.send(cmd.encode("utf-8"))

    if cmd == "q":
        break

    data = client.recv(1024)
    print(data.decode("gbk"))

client.close()

終端打印結果server

請輸入>>>tasklist

映像名稱                       PID 會話名              會話#       內存使用 
========================= ======== ================ =========== ============
System Idle Process              0 Services                   0         24 K
System                           4 Services                   0      3,172 K
smss.exe                       352 Services                   0      1,200 K
csrss.exe                      464 Services                   0      6,656 K
wininit.exe                    572 Services                   0      5,168 K
csrss.exe                      588 Console                    1     77,948 K
services.exe                   636 Services                   0     12,288 K
lsass.exe                      652 Services                   0     11,164 K
lsm.exe                        660 Services                   0      4,664 K
winlogon.exe                   744 Console                    1      8,180 K
svchost.exe                    812 Services                   0     10,040 K
svchost.
請輸入>>>dir
exe                    892 Services                   0      8,280 K
svchost.exe                    980 Services                   0     21,744 K
svchost.exe                    168 Services                   0     21,060 K
svchost.exe                    388 Services                   0     40,792 K
svchost.exe                    908 Services                   0     12,252 K
WUDFHost.exe                  1100 Services                   0      8,096 K
ZhuDongFangYu.exe             1188 Services                   0     23,784 K
svchost.exe                   1236 Services                   0     17,532 K
wlanext.exe                   1412 Services                   0      5,268 K
conhost.exe                   1420 Services                   0      2,860 K
dwm.exe                       1536 Console                    1     38,436 K
explorer.exe                  1588 Console                    1     70,028 K
spoolsv.exe                   1612 Services                   0     12,204 K
svchost.exe

咱們看到在輸完tasklist 命令以後,再次輸入其餘命令,仍是上次命令的結果,

那麼久證實了 服務端第一次發送的數據,客戶端沒法準確一次性的接收完畢,下一次發送的數據與上一次數據粘在一塊兒。咱們在客戶端接收的時候,接收的數據大小是1024個字節,服務器執行結果 超出了接收的大小,因此至關於把結果堆到了後面,一塊兒發送,因此下次執行命令得不到正確的結果,那麼咱們須要解決這個問題就須要用到 struct 模塊

struct模塊

struct 模塊必須先定義報頭,,先發送報頭,再發送真實數據

# 服務端
# coding=utf-8

import struct
import socket
import subprocess

server = socket.socket()
address = ("127.0.0.1",8888)
server.bind(address)
server.listen(5)

while True:
    conn,addr = server.accept()
    while True:
        try:
            cmd = conn.recv(1024).decode("utf-8")
            print(cmd)

            if cmd == "q":
                break

            obj = subprocess.Popen(
                cmd ,shell=True,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE
            )

            res = obj.stdout.read() + obj.stderr.read()
            
            # 將執行結果計算長度用i模式打包
            res_len = struct.pack("i",len(res))

            # 先發送數據長度
            conn.send(res_len)

            # 再發送真實數據
            conn.send(res)
        except Exception:
            break
    conn.close()
# 客戶端
# coding=utf-8

import socket
import struct


client = socket.socket()
address = ("127.0.0.1",8888)
client.connect(address)

while True:
    cmd = input("請輸入命令>>>")
    client.send(cmd.encode("utf-8"))
    if cmd == "q":
        break
    
    # 用struct模塊接收的長度統一是4個字節,
    head = client.recv(4)
    # 而後用struct模塊解包獲得數據的真實長度,返回的是元組類型,0表示第一個元素,就是真實長度
    data_len = struct.unpack("i",head)[0]
    
    # 而後再把真實長度接收便可。
    data = client.recv(data_len)
    print(data.decode("gbk"))
client.close()

UDP協議編程

udp也是一種傳輸協議

1)不須要創建雙向通道

2)不會粘包

3)客戶端給服務端發送數據,不須要等待服務端返回接收成功

4)數據容易丟失,數據不安全。

TCP:就至關於與在打電話

UDP:就至關於與在發短信

簡易qq聊天室

# 服務端
# coding=utf-8
import socket

server = socket.socket(type=socket.SOCK_DGRAM)
address = ("127.0.0.1",8888)
server.bind(address)

while True:
    msg,addr = server.recvfrom(1024)
    print(msg.decode("utf-8"))

    # 服務端往客戶端發送消息
    send_msg = input("服務端發送消息")
    server.sendto(send_msg.encode("utf-8"),addr)
# 客戶端
# coding=utf-8
import socket
client = socket.socket(type=socket.SOCK_DGRAM)
address = ("127.0.0.1",8888)

while True:
    send_msg = input("請輸入信息")
    client.sendto(send_msg.encode("utf-8"),address)

    data = client.recv(1024)
    print(data.decode("utf-8"))
相關文章
相關標籤/搜索