socket套接字及粘包問題

socket套接字

一、什麼是socket

socket是一個模塊,又稱套接字,用來封裝互聯網協議(應用層如下的層)python

二、爲何要有socket

實現應用層如下的層的工做,提升開發效率shell

三、怎麼使用socket

先導入socket模塊,先啓動服務端套接字,再啓動客戶端套接字json

# 服務端

import socket
# 買手機
server = socket.socket()
# 綁定手機號(IP,port)
# IP單機模式是127.0.0.1,局域網內使用cmd中ipconfig查詢IPV4
# port設置8000之後的數據
server.bind(('127.0.0.1', 9876))
# 設置半鏈接池
server.listen(4)
# 可接收多個客戶端數據鏈接,實現循環通訊
while True:
    # 接收客戶端鏈接
    conn, addr = server.accept()
    # 查看對方地址
    print(addr)
    while True:
        # 捕獲異常機制
        try:
            # 接收客戶端發來的數據,可一次接收1024bytes的數據
            data = conn.recv(1024)
            if len(date) == 0:
                break
            if data.decode('utf-8') == 'q':
                break
            print(data.decode('utf-8'))
            # 向客戶端發送消息
            send_data = input('請輸入向客戶端發送的數據:')
            conn.send(send_data.encode('utf-8'))
        # 捕獲異常,並打印出錯誤信息
        except Exception as e:
            print(e)
            break
    # 掛電話
    conn.close()
# 客戶端

import socket
# 買手機
client = socket.socket()
# 創建鏈接(IP,port)
client.connect(('127.0.0.1',9876))
while True:
    try:
        # 向對方發送數據
        data = input('請輸入向服務端發送的數據')
        client.send((data.encode('utf--8')))
        # 接收對方發來的數據可設置一次接收的bytes數,並打印
        res_data = client.recv(1024)
        if len(res_data) == 0:
            break
        if res_data.decode('utf-8') == 'q':
            break
        print(res_data.decode('utf-8'))
    # 捕獲異常,並打印出異常
    except Exception as e:
        print(e)
        break
client.close()

粘包問題

問題1:

沒法確認對方發送過來數據大小併發

問題2:

在發送數據間隔短而且數據量小的狀況下,會將全部數據一次性發送socket

解決:須要確認對方發送的數據大小code

# 客戶端
# 問題1
import socket
client = socket.socket()
client.connect(('127.0.0.1', 9876))
while True:
    try:
        cmd = input('請輸入向服務端發送的命令:')
        client.send(cmd.encode('utf-8'))
        # 接收服務端返回的數據
        # 因爲不知道會返回多少個bytes因此有問題1
        date = client.recv(11910)
        print(len(date))
        print(date.decode('gbk'))
    except Exception as e:
        print(e)
        break
client.close()
# 客戶端
# 問題2
# 時間間隔短,並數據量小的狀況下,會將全部的數據一次性發送,接收時不知道具體有幾個
import socket
client = socket.socket()
client.connect(('127.0.0.1', 9876))
client.send(b'hello')
client.send(b'hello')
client.send(b'hello')
client.send(b'hello')
client.send(b'hello')
# 服務端

import socket
import subprocess

server = socket.socket()
server.bind(('127.0.0.1', 9876))
server.listen(4)
while True:
    conn, addr = server.accept()
    print(addr)

    while True:
        try:
            # 接收客戶端的數據,具體值不知道多大,全部有可能不能徹底接收,有可能浪費資源
            cmd = conn.recv(12)
            if len(cmd) == 0:
                break
            cmd = cmd.decode('utf-8')
            if cmd == 'q':
                break
            # 調用subprocess鏈接終端,對終端進行操做,並獲取正確和錯誤的結果
            obj = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            # 拿到結果,並打印
            result = obj.stdout.read() + obj.stderr.read()
            print(result.decode('gbk'))
            # 將結果返回給客戶端
            conn.send(result)

        except Exception as e:
            print(e)
            break
    conn.close()

解決粘包問題

使用struct模塊server

struct 是一個python內置的模塊,它能夠將固定長度的數據,打包成固定格式的長度ip

模式:i:4,或其餘模式utf-8

做用:將真實數據作成一個固定長度的報頭,發送給服務端,服務端接收報頭,而後進行解包,獲取真實數據的長度,進行接收數據便可資源

import struct
data = input('請輸入傳的數據').strip()
data = data.encode('utf-8')
# 製做報頭,須要 i 的字符串和傳入數據的長度
header = struct.pack('i',len(data))
print(header)
print(len(header))

# 解包( i 的字符串和報頭)獲取真實長度,獲得一個元組,拿到元組第一個數就是真實長度
res = struct.unpack('i', header)[0]
print(res)

# utf-8中一箇中文是3個bytes,一個英文是1個bytes

客戶端:

​ 1.先製做報頭,併發送

​ 2.發送真實數據

服務端:

​ 1.接收報頭,而且解包獲取真實數據長度

​ 2.根據真實數據長度,接收真實數據

# 客戶端
import socket
import struct

client = socket.socket()
client.connect(('127.0.0.1', 9876))
while True:
    try:
        cmd = input('請輸入向服務端發送的命令')
        cmd_bytes = cmd.encode('utf-8')
        # 作一個報頭
        header = struct.pack('i', len(cmd_bytes))
        # 發送報頭
        client.send(header)
        # 發送真實數據
        client.send(cmd_bytes)
        # 接受服務端返回的報頭
        reheader = client.recv(4)
        # 解包
        data_len = struct.unpack('i', reheader)[0]
        result = client.recv(data_len)
        print(result.decode('gbk'))
    except Exception as e:
        print(e)
        break
client.close()
# 服務端
import socket
import subprocess
import struct

server = socket.socket()
server.bind(('127.0.0.1', 9876))
server.listen(5)
while True:
    conn, addr = server.accept()
    while True:
        try:
            # 獲取報頭
            header = conn.recv(4)
            # 獲取真實數據長度
            data_len = struct.unpack('i', header)[0]
            # 準備接受真實數據
            cmd = conn.recv(data_len)
            cmd = cmd.decode('utf-8')
            if cmd == 'q':
                break
            if len(cmd) == 0:
                break
            obj = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            result = obj.stdout.read() + obj.stderr.read()
            print(len(result))
            print(result.decode('gbk'))
            # 將結果返回給客戶端
            header = struct.pack('i', len(result))
            conn.send(header)
            conn.send(result)
        except Exception as e:
            print(e)
            break
    conn.close()
# 客戶端
import socket
import struct
import json
client = socket.socket()
client.connect(('127.0.0.1', 9876))
while True:
    # 假裝電影數據
    movie_name = input('請輸入電影名稱:')
    movie_len = 10000101
    send_dic = {
        'movie_name': movie_name,
        'movie_len': movie_len
    }
    # 序列化
    json_data = json.dumps(send_dic)
    # 製做報頭
    json_bytes = json_data.encode('utf-8')
    header = struct.pack('i', len(json_bytes))
    # 發送報頭
    client.send(header)
    # 發送真實數據
    client.send(json_bytes)
# 服務端
import socket
import json
import struct

server = socket.socket()
server.bind(('127.0.0.1', 9876))
server.listen(5)
while True:
    conn, addr = server.accept()
    print(addr)
    while True:
        try:
            # 接收報頭
            header = conn.recv(4)
            # 解包獲取真實長度
            json_len = struct.unpack('i', header)[0]
            # 接收真實長度
            json_bytes_data = conn.recv(json_len)
            json_data = json_bytes_data.decode('utf-8')
            # 反序列化獲得數據
            back_dic = json.loads(json_data)
            print(back_dic)
        except Exception as e:
            print(e)
            break
    conn.close()
相關文章
相關標籤/搜索