黏包

目錄

1.黏包的問(wèn)題
2.解決黏包問(wèn)題
3.文件上傳下載
4.struct模塊使用

1.黏包的問(wèn)題

#CMD服務(wù)端
import  socket
import subprocess
import struct
server = socket.socket()
server.bind(("127.0.0.1",9090))
server.listen()

while True:
    client,addr = server.accept()
    while True:
        try:
            # 接收命令
            cmd = client.recv(1024).decode("utf-8")
            p = subprocess.Popen(cmd,shell=True,stdout=-1,stderr=-1)
            # data與err_data 都是采用的系統(tǒng)編碼 windows是GBK
            data = p.stdout.read()
            err_data = p.stderr.read()

            print("數(shù)據(jù)長(zhǎng)度:%s" % (len(data)   + len(err_data)))

            # 先發(fā)送長(zhǎng)度給客戶端
            length = len(data)   + len(err_data)

            len_data = struct.pack("i",length)
            # 先發(fā)送長(zhǎng)度 在發(fā)真實(shí)數(shù)據(jù) 有可能 長(zhǎng)度數(shù)據(jù)和真實(shí)數(shù)據(jù)黏在一起 而接收方不知道長(zhǎng)度數(shù)據(jù)的字節(jié)數(shù) 導(dǎo)致黏包
            # 解決的方案就是 長(zhǎng)度信息占的字節(jié)數(shù)固定死  整數(shù) 轉(zhuǎn)成一個(gè)固定長(zhǎng)度字節(jié)

            client.send(len_data)

            client.send(data)
            client.send(err_data)
        except ConnectionResetError:
            client.close()
            print("連接中斷......")
            break

#CMD客戶端
import struct
import socket

c = socket.socket()
c.connect(("127.0.0.1",9090))
while True:
    cmd = input(">>:").strip()

    c.send(cmd.encode("utf-8"))

    # 先接收長(zhǎng)度  長(zhǎng)度固定為4個(gè)字節(jié)
    length = c.recv(4)
    len_data = struct.unpack("i",length)[0] # 轉(zhuǎn)換為整型
    print("數(shù)據(jù)長(zhǎng)度為%s" % len_data)

    all_data = b"" # 存儲(chǔ)已接收數(shù)據(jù)
    rcv_size = 0 # 已接收長(zhǎng)度
    # 接收真實(shí)數(shù)據(jù)
    # 循環(huán)接收 直到 接收到的長(zhǎng)度等于總長(zhǎng)度
    while  rcv_size < len_data:
        data = c.recv(1024)
        rcv_size += len(data)
        all_data += data

    print("接收長(zhǎng)度%s" % rcv_size)
    print(all_data.decode("gbk"))

2.解決黏包問(wèn)題

#CMD服務(wù)端
import  socket
import subprocess
import struct
import datetime
import json

server = socket.socket()
server.bind(("127.0.0.1",9090))
server.listen()

# 要求  不僅返回命令的結(jié)果 還要返回執(zhí)行命令的時(shí)間  執(zhí)行時(shí)間:2018/12/26

while True:
    client,addr = server.accept()
    while True:
        try:
            # 接收命令
            cmd = client.recv(1024).decode("utf-8")
            p = subprocess.Popen(cmd,shell=True,stdout=-1,stderr=-1)
            # data與err_data 都是采用的系統(tǒng)編碼 windows是GBK
            data = p.stdout.read()
            err_data = p.stderr.read()

            print("數(shù)據(jù)長(zhǎng)度:%s" % (len(data)   + len(err_data)))
            # 計(jì)算真實(shí)數(shù)據(jù)長(zhǎng)度
            length = len(data)   + len(err_data)


            # 在發(fā)送數(shù)據(jù)之前發(fā)送額外的信息
            #t = "{執(zhí)行時(shí)間:%s 真實(shí)數(shù)據(jù)長(zhǎng)度:%s" % (datetime.datetime.now(),length)
            # 把要發(fā)送的數(shù)據(jù)先存到字典中
            t = {}
            t["time"] = str(datetime.datetime.now())
            t["size"] = length
            t["filename"] = "a.mp4"


            t_json = json.dumps(t) # 得到j(luò)son格式字符串
            t_data = t_json.encode("utf-8") # 將json轉(zhuǎn)成了字節(jié)
            t_length = struct.pack("i",len(t_data))



            # 1.先發(fā)送額外信息的長(zhǎng)度
            client.send(t_length)
            # 2.發(fā)送額外信息
            client.send(t_data)

            # 3.發(fā)送真實(shí)數(shù)據(jù)
            client.send(data)
            client.send(err_data)
        except ConnectionResetError:
            client.close()
            print("連接中斷......")
            break


#  1.發(fā)送了真實(shí)數(shù)據(jù)長(zhǎng)度   2.發(fā)送了額外信息長(zhǎng)度  3.發(fā)送額外信息  4.真實(shí)數(shù)據(jù)

#CMD客戶端
import struct
import socket
import json

c = socket.socket()
c.connect(("127.0.0.1",9090))
while True:
    cmd = input(">>:")
    if not cmd:
        print("命令不能為空")
        continue
    c.send(cmd.encode("utf-8"))

    # 1.接收的是額外信息的長(zhǎng)度
    length = c.recv(4)
    len_data = struct.unpack("i",length)[0] # 轉(zhuǎn)換為整型

    # 2.接收額外信息
    t_data = c.recv(len_data)
    print(t_data.decode("utf-8"))

    json_dic = json.loads(t_data.decode("utf-8"))
    print("執(zhí)行時(shí)間:%s" % json_dic["time"])

    data_size = json_dic["size"] # 得到數(shù)據(jù)長(zhǎng)度


    # 3.接收真實(shí)數(shù)據(jù)
    all_data = b"" # 存儲(chǔ)已接收數(shù)據(jù)
    rcv_size = 0 # 已接收長(zhǎng)度
    # 接收真實(shí)數(shù)據(jù)
    # 循環(huán)接收 直到 接收到的長(zhǎng)度等于總長(zhǎng)度
    while  rcv_size < data_size:
        data = c.recv(1024)
        rcv_size += len(data)
        all_data += data

    print("接收長(zhǎng)度%s" % rcv_size)
    print(all_data.decode("gbk"))

3.文件上傳下載

"""
    1.應(yīng)該采用TCP  必須保證數(shù)據(jù)時(shí)完整的
    2.只能傳輸bytes類型  剛好 文件操作 讀取和寫入都是bytes類型
    3.上傳的思路
        自定義報(bào)頭 發(fā)送文件名 文件大小 md5值
        讀取文件數(shù)據(jù)  發(fā)送給對(duì)方
"""
#服務(wù)端
import  socket
import  struct
import  json
server = socket.socket()
server.bind(("127.0.0.1",9090))
server.listen()
client,addr = server.accept()

f =  open("接收到的文件",mode="wb")

head_len = client.recv(4)
json_len = struct.unpack("i",head_len)[0]

json_str = client.recv(json_len).decode("utf-8")
head = json.loads(json_str)
print(head)


recv_size = 0
while recv_size < head["size"]:
    data = client.recv(1024)
    f.write(data)
    recv_size += len(data)

print("接收完成...")

#客戶端
import socket
import os
import json
import struct
c = socket.socket()
c.connect(("127.0.0.1",9090))

filepath=  r"D:\脫產(chǎn)5期內(nèi)容\day30\視頻\1.上周回顧.mp4"
f = open(filepath,mode="rb")

# 在發(fā)送數(shù)據(jù)前先發(fā)送報(bào)頭
head = {"size":os.path.getsize(filepath),"filename":"回顧.mp4"}
json_data = json.dumps(head).encode("utf-8")

json_len = struct.pack("i",len(json_data))
c.send(json_len) # 發(fā)長(zhǎng)度
c.send(json_data) # 發(fā)報(bào)頭

# 發(fā)數(shù)據(jù)
while True:
    data = f.read(1024)
    if not data:
        break
    # 發(fā)送給服務(wù)器
    c.send(data)

print("上傳完成...")

4.struct模塊的使用

"""
    struct結(jié)構(gòu)體
    可以將python中的數(shù)據(jù)類型 轉(zhuǎn)換成bytes

"""
num = 1024

import struct

# 該函數(shù) 將一個(gè)python的數(shù)據(jù)轉(zhuǎn)成bytes   第一個(gè)參數(shù)通常是i 其能轉(zhuǎn)換的數(shù)據(jù)范圍是c語(yǔ)言的int范圍
# 如果int不夠 那就用q  表示long long 型
res = struct.pack("i",num)
print(res)
print(len(res))


# 從字節(jié)轉(zhuǎn)回整型
res2 = struct.unpack("i",res)
print(res2[0])
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末袍睡,一起剝皮案震驚了整個(gè)濱河市署尤,隨后出現(xiàn)的幾起案子疗涉,更是在濱河造成了極大的恐慌脐帝,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,324評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件仆百,死亡現(xiàn)場(chǎng)離奇詭異厕隧,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)俄周,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門吁讨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人峦朗,你說(shuō)我怎么就攤上這事建丧。” “怎么了波势?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,328評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵翎朱,是天一觀的道長(zhǎng)橄维。 經(jīng)常有香客問(wèn)我,道長(zhǎng)拴曲,這世上最難降的妖魔是什么争舞? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,147評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮澈灼,結(jié)果婚禮上竞川,老公的妹妹穿的比我還像新娘。我一直安慰自己蕉汪,他們只是感情好流译,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,160評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布逞怨。 她就那樣靜靜地躺著者疤,像睡著了一般。 火紅的嫁衣襯著肌膚如雪叠赦。 梳的紋絲不亂的頭發(fā)上驹马,一...
    開(kāi)封第一講書(shū)人閱讀 51,115評(píng)論 1 296
  • 那天,我揣著相機(jī)與錄音除秀,去河邊找鬼糯累。 笑死,一個(gè)胖子當(dāng)著我的面吹牛册踩,可吹牛的內(nèi)容都是我干的泳姐。 我是一名探鬼主播,決...
    沈念sama閱讀 40,025評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼暂吉,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼胖秒!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起慕的,我...
    開(kāi)封第一講書(shū)人閱讀 38,867評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤阎肝,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后肮街,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體风题,經(jīng)...
    沈念sama閱讀 45,307評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,528評(píng)論 2 332
  • 正文 我和宋清朗相戀三年嫉父,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了沛硅。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,688評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡绕辖,死狀恐怖摇肌,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情引镊,我是刑警寧澤朦蕴,帶...
    沈念sama閱讀 35,409評(píng)論 5 343
  • 正文 年R本政府宣布篮条,位于F島的核電站,受9級(jí)特大地震影響吩抓,放射性物質(zhì)發(fā)生泄漏涉茧。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,001評(píng)論 3 325
  • 文/蒙蒙 一疹娶、第九天 我趴在偏房一處隱蔽的房頂上張望伴栓。 院中可真熱鬧,春花似錦雨饺、人聲如沸钳垮。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,657評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)饺窿。三九已至,卻和暖如春移斩,著一層夾襖步出監(jiān)牢的瞬間肚医,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,811評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工向瓷, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留肠套,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,685評(píng)論 2 368
  • 正文 我出身青樓猖任,卻偏偏與公主長(zhǎng)得像你稚,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子朱躺,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,573評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • 基于tcp協(xié)議傳輸數(shù)據(jù)的時(shí)候刁赖,如果接收端單次接收的數(shù)據(jù)長(zhǎng)度小于發(fā)送的總長(zhǎng)度,則會(huì)導(dǎo)致部分?jǐn)?shù)據(jù)無(wú)法接收全室琢,在第二次接...
    阿bai君閱讀 270評(píng)論 0 0
  • 黏包 最近一直再看python的網(wǎng)絡(luò)編程乾闰,黏包問(wèn)題是TCP協(xié)議所獨(dú)有的一種問(wèn)題,自己平時(shí)也有些理解方面的不清晰盈滴,所...
    漓江塔塔主閱讀 709評(píng)論 0 0
  • 注意:只有TCP有粘包現(xiàn)象涯肩,UDP永遠(yuǎn)不會(huì)粘包 黏包的原因一: udp接受一個(gè)數(shù)據(jù)包的代碼ret, addr = ...
    Yanl__閱讀 177評(píng)論 0 0
  • 用到的組件 1、通過(guò)CocoaPods安裝 2巢钓、第三方類庫(kù)安裝 3病苗、第三方服務(wù) 友盟社會(huì)化分享組件 友盟用戶反饋 ...
    SunnyLeong閱讀 14,613評(píng)論 1 180
  • 用兩張圖告訴你,為什么你的 App 會(huì)卡頓? - Android - 掘金 Cover 有什么料症汹? 從這篇文章中你...
    hw1212閱讀 12,712評(píng)論 2 59