ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

粘包问题以及解决方法

2020-03-29 16:09:24  阅读:199  来源: 互联网

标签:socket 方法 send server client 解决 import 粘包 data


目录

subprocess模块

1.可以帮你通过代码执行操作系统的终端命令

2.并返回终端执行命令后的结果

注意:stdout一定要在stderr前面

import subprocess

cmd=input('cmd>>>:')

obj=subprocess.Popen(
    cmd,shell=True,
    stdout=subprocess.PIPE,#返回正确结果参数
    stderr=subprocess.PIPE#返回错误结果参数
)

result=obj.stdout.read()+obj.stderr.read()
print(result.decode('gbk'))

粘包问题

服务端第一次发送的数据,客户端无法精确一次性接受完毕。下一次发送的数据与上一次数据粘在一起了。

1.无法预测对方需要接受的数据大小长度

2.多次连续发送数据量小,并且时间间隔短的数据一次性打包发送

TCP协议特性:

​ tcp是一个流式协议,会将多次连续发送数据量小,并且时间间隔短的数据一次性打包发送

解决粘包问题

struct模块

是一个可以将很长的数据长度,压缩成固定的长度的一个标记(数据报头)。

必须先定义报头,发送报头,再发送真实数据

即想发送文件,又想发送文件的描述信息

'''
-struct模块:
    是一个可以将很长的数据的长度,压缩成固定的长度的一个标记(数据报头)
'''
import struct
#打包压缩
# i模式,会将数据长度压缩成4个bytes
str1='nihaoyanihaoyanihaoya'

# 报头

headers=struct.pack('i', len(str1))

data_len=struct.unpack('i',headers)
print(data_len)#(21,)
print(data_len[0])#21

解决粘包问题

#服务端
import socket
import subprocess
import struct

server=socket.socket()

server.bind(('127.0.0.1',9527))

server.listen(5)

while True:
    conn,addr=server.accept()
    while True:
        try:

            cmd=conn.recv(1024).decode('utf-8')
            if cmd=='q':
                break

            if len(cmd)==0:
                continue

            print(cmd)
            # 执行cmd命令
            obj=subprocess.Popen(cmd,shell=True,
                                 stderr=subprocess.PIPE,
                                 stdout=subprocess.PIPE,)
            #接受终端返回的数据
            result=obj.stdout.read()+obj.stderr.read()
            #打包压缩,获取报头
            headers=struct.pack('i',len(result))
            #发送报头
            conn.send(headers)
            #发送真实数据
            conn.send(result)
        except Exception as e:
            print(e)
            break
    conn.close()
#客户端
import socket
import struct

client=socket.socket()

client.connect(('127.0.0.1',9527))

while True:
    cmd=input('>>>:')

    client.send(cmd.encode('utf-8'))

    if cmd=='q':
        break
    #获取数据报头
    headers=client.recv(4)
    #解包,获取真实数据长度
    data_len=struct.unpack('i',headers)
    #获取真实数据
    data=client.recv(data_len[0])

    print(data.decode('gbk'))
client.close()

上传字典

#服务端
import socket
import json
import struct

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

while True:
    conn,addr=server.accept()
    while True:
        try:
            headers=conn.recv(4)
            data_len=struct.unpack('i',headers)[0]
            bytes_data=conn.recv(data_len)
            #先解码再反序列化
            back_dic=json.loads(bytes_data.decode('utf-8'))
            print(back_dic)
        except Exception as e:
            print(e)
            break
    conn.close()
#客户端
import socket
import struct
import json
import time

cilent=socket.socket()
cilent.connect(('127.0.0.1',8888))
while True:
    send_dic={
        'file_name':'nick真实写真集.avi',
        'file_size':1000000
    }
    #json序列化,并转换成bytes类型数据
    json_data=json.dumps(send_dic)
    bytes_data=json_data.encode('utf-8')

    # 先做报头
    headers=struct.pack('i',len(bytes_data))
    cilent.send(headers)
    cilent.send(bytes_data)
    time.sleep(3)

上传大文件

#服务端
import socket
import json
import struct

server=socket.socket()

server.bind(('127.0.0.1',8888))

server.listen(3)
while True:
    conn,addr=server.accept()
    while True:
        try:
            #获取字典报头
            headers=conn.recv(4)
            #解包获取字典数据长度
            data_len=struct.unpack('i',headers)[0]
            #获取字典真实数据
            bytes_dic=conn.recv(data_len)
            #樊=反序列得到字典
            back_dic=json.loads(bytes_dic.decode('utf-8'))
            print(back_dic)
            #得到字典的文件名以及视频文件按的大小
            file_name=back_dic['file_name']
            file_size=back_dic['file_size']

            init_data=0
            #打开文件 准备写入
            with open(file_name,'wb') as f:
                while init_data<file_size:
                    data=conn.recv(1024)
                    f.write(data)
                    init_data+=len(data)
                    num=init_data/file_size
                    print(f'已接受{num:.2%}')
                print(f'{file_name}接收完毕')
        except Exception as e:
            print(e)
            break
    conn.close()
#客户端
import socket
import struct
import json

client=socket.socket()
client.connect(('127.0.0.1',8888))

#打开一个视频文件,获取视频数据大小
with open(r'C:\Users\zqf\Desktop\新建文件夹\八重樱_桃源恋歌_1080p.mp4','rb') as f:
    movie_bytes=f.read()

# 为视频文件组织一个字典,字典内有视频文件按的名称和大小
send_dic={
    'file_name':'八重樱-桃源恋歌',
    'file_size':len(movie_bytes)
}

# 先打包字典 发送报头,再发送字典真实数据
json_data=json.dumps(send_dic)
bytes_data=json_data.encode('utf-8')
headers=struct.pack('i',len(bytes_data))

# 发送报头
client.send(headers)
#发送字典真实数据
client.send(bytes_data)

# 发送视频真实数据
init_data=0
with open(r'C:\Users\zqf\Desktop\新建文件夹\八重樱_桃源恋歌_1080p.mp4','rb') as f:
    while init_data<len(movie_bytes):
        send_data=f.read(1024)
        client.send(send_data)
        num=init_data/len(movie_bytes)
        print(f'数据传输{num:.2%}')
        init_data+=len(send_data)

UDP

是一种传输协议

1.不需要建立双向管道

2.不会粘包

3.客户端给服务端发送数据,不需要等待服务端返回接受成功

4.数据容丢失,数据不安全

-TCP:好比打电话

-UDP:好比发短信

#服务端
import socket
#.SOCK_DGRAM代表了UDP
server=socket.socket(type=socket.SOCK_DGRAM)
#绑定了ip+port
server.bind(('127.0.0.1',8888))

msg,addr=server.recvfrom(1024)
msg1,addr1=server.recvfrom(1024)
msg2,addr2=server.recvfrom(1024)

print(msg,msg1,msg2)

#客户端
import socket

client=socket.socket(type=socket.SOCK_DGRAM)

server_ip_port=(('127.0.0.1',8888))

client.sendto(b'hello',server_ip_port)
client.sendto(b'hello',server_ip_port)
client.sendto(b'hello',server_ip_port)
client.sendto(b'hello',server_ip_port)
client.sendto(b'hello',server_ip_port)

QQ聊天室

#服务端
import socket

server=socket.socket(type=socket.SOCK_DGRAM)

server.bind(('127.0.0.1',8888))

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

    send_msg=input("客户端向服务端发消息").encode('utf-8')
    server.sendto(send_msg,addr)
#客户端
import socket

client=socket.socket(type=socket.SOCK_DGRAM)

server_ip_port=('127.0.0.1',8888)
while True:
    send_msg=input('客户端向服务端发消息').encode('utf-8')
    client.sendto(send_msg,server_ip_port)

    msg=client.recv(1024)
    print(msg.decode('utf-8'))

SocketServer

python内置模块,可以简化socket套接字服务端代码

-简化TCP/UDP服务代码

-必须要创建一个类

#服务端
import socketserver

#必须定义类
#TCP:必须继承BaseRequestHandler类
class MyTcpServer(socketserver.BaseRequestHandler):
    def handle(self):
        print(self.client_address)
        while True:
            try:
                #request.recv==conn.recv
                data=self.request.recv(1024).decode('utf-8')
                send_msg=data.upper()
                self.request.send(send_msg.encode('utf-8'))

            except Exception as e:
                print(e)
                break

if __name__ == '__main__':
    #socketserver.TCPServer只能一个服务
    # server=socketserver.TCPServer(
    #     ('127.0.0.1',8888),MyTcpServer
    # )
    #
    #socketserver.ThreadingTCPServer 多个服务
    server=socketserver.ThreadingTCPServer(
        ('127.0.0.1', 8888), MyTcpServer
    )
    server.serve_forever()
#客户端
import socket
client=socket.socket()

client.connect(
    ('127.0.0.1',8888)
)
while True:
    send_msg=input('客户端:')
    client.send(send_msg.encode('utf-8'))
    back_msg=client.recv(1024)
    print(back_msg.decode('utf-8'))


标签:socket,方法,send,server,client,解决,import,粘包,data
来源: https://www.cnblogs.com/zqfzqf/p/12592739.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有