python 网络编程之TCP传输&粘包传输

只有TCP有粘包现象,UDP永远不会粘包。

所谓粘包问题主要还是C/S两端数据传输时 因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的

 


根本原因:
粘包是由TCP协议本身造成的,TCP为提高传输效率,发送方往往要收集到足够多的数据后才发送一个TCP段。若连续几次需要send的数据都很少,通常TCP会根据优化算法把这些数据合成一个TCP段后一次发送出去,这样接收方就收到了粘包数据。

解决方法:

1、自定义字典类型 的数据报头{文件名:a,文件的size:1090}计算出该报头的长度(len(字节)),

2、使用
struct.pack('i',报头长度(一个数字))把一个数字压缩成固定的size 4个字节,发送给对端。

3、对端 struct.unpack(‘i’,recv(4))接收固定大小4个字节;这就是接收到了 报头的长度。

4.recv(报头长度)这就是发送过来的报头信息了


import struct
a='您好'
a=len(a.encode('utf-8'))   #字节的长度=====这个数据有多大字节
                            # 1英文字母utf-8编码后=1字节
#                           #1中文字符 utf-8编码后=3个字节a=struct.pack('i',a)        #struct.pack把数字转换成 固定大小 4个字节的 字节
print(len(a))                #4个字节
print(struct.unpack('i',a)[0]) #struct.unpack[0] 解报头,索引第一个

 






服务端
import socket
import struct
import json
phon=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phon.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
phon.bind(("127.0.0.1",8090))
phon.listen(80)                 #
while True:
    conn,addr=phon.accept()
    while True:
        try:
            data=conn.recv(4)      #接受4个字节的报头
            data=struct.unpack('i',data)[0]
            data1=conn.recv(data).decode('utf-8')  #接受 字节类型的报头信息
                                                    #{"file_name": "\u4f60\u597d", "file_size": 6}
            data1=json.loads(data1)
            print(data1)
            da=conn.recv(data1['file_size']).decode('utf-8') #接收真实数据
            print(da)
  
            conn.send('sss'.encode('utf-8'))    #发送接受的消息 给某一个客户端
        except Exception:
            break
    conn.close()
phon.close()
客户端
import socket
import struct
import json
phon=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phon.connect(('127.0.0.1',8090))     #客户端的phon.connect正好对于服务端的phon1.accept()
while True: #循环通信
    mes=input('---->: '.strip())
    if not mes:
        continue
    mes = mes.encode('utf-8')
    mes_len = len(mes)
    head = {'file_name': mes.decode('utf-8'), 'file_size': mes_len}
    head_json = json.dumps(head)  # {"file_name": "a", "file_size": 1}
    head_bytes = head_json.encode('utf-8')
    head_bytes_len = len(head_bytes)  # 51
    struct1 = struct.pack('i',head_bytes_len)
    send_=phon.send(struct1)  #发送4个字节的 报头长度
    data=phon.send(head_bytes) #发送报头
    da=phon.send(mes)          #发送真实数据


phon.close()

参考&相关资料:

https://www.cnblogs.com/sss4/p/6807515.html  --简单

https://www.cnblogs.com/guobaoyuan/p/6809447.html  --更详细

https://gist.github.com/kevinkindom/108ffd675cb9253f8f71

posted @ 2019-02-22 15:16  戒骄戒躁-沉淀积蓄  阅读(674)  评论(0编辑  收藏  举报