socket套接字 tcp协议下的粘包处理

socket套接字初识:

服务端: import socket server = socket.socket() #买手机 server.bind(('127.0.0.1', 11090)) #插手机卡 bind(IP,PORT) #127.0.0.1:本地回环地址,只能本机访问 server.listen(5) #开机,半连接池 conn, addr = server.accept() #待机等待接电话 三次握手完成 data=conn.recv(1024) #接听别人电话,只接收1024个字节 bytes print(data) conn.send(b'hello wrold!') #跟别人说话 conn.close() #关闭通信连接 server.close()#关闭服务器 客户端: import socket client = socket.socket() #不传参数默认为TCP协议 client.connect(('127.0.0.1', 11090)) #找服务器 client.send(b'hello') data = client.recv(1024) print(data) client.close()

  

struct的简单使用

import struct
data='123456'
data=struct.pack('i', len(data))
print(len(data)) #4
ret=struct.unpack('i', data)[0]
print(ret)      #6

  

subprocess 与 tasklist 的配合使用

import subprocess

obj = subprocess.Popen('tasklist',
                       shell=True,
                       stdout=subprocess.PIPE,
                       stderr=subprocess.PIPE)
stdout = obj.stdout.read()
print('stdout',stdout.decode('gbk'))
stderr = obj.stderr.read()
print('stderr',stderr.decode('gbk'))

  

解决粘包的方法:


服务端:
import socket
import struct
import json
import subprocess


server = socket.socket()
server.bind(('127.0.0.1', 8090))
server.listen(5)
while True:
    conn,addr = server.accept()
    while True:
        try:
            data = conn.recv(1024).decode('utf-8')
            # if len(data) == 0:break
            obj = subprocess.Popen(data,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
            stdout = obj.stdout.read()
            stderr = obj.stderr.read()
            print(len(stdout+stderr))   #打印真实数据长度

            head_dic={
                'filename':'cls.av',
                'len':len(stdout+stderr)
            }

            header_bytes=json.dumps(head_dic).encode('utf-8')
            #制作报头
            header=struct.pack('i', len(head_dic))  #打包为4个字节       此处len()括号里应该为len(header_bytes)
            conn.send(header)  #先发报头
            conn.send(header_bytes) #再发字典
            conn.send(stderr+stdout) #最后发真实数据        #此处的stdout与stderr均是字节类型
        except ConnectionResetError:
            break
    conn.close()



客户端:
import json
import socket
import struct


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

while True:
    msg = input('>>>:').encode('utf-8')  #字符串编码为字节
    if len(msg) == 0: continue
    client.send(msg)   #发送原始数据
    header = client.recv(4) #接收4个长度的报头
    head_len = struct.unpack('i', header)[0]  #解压拿到字典数据长度
    head_dic = json.loads(client.recv(head_len).decode('utf-8'))
    #接收字典里真实长度的字节解码后反序列化的所有信息
    print(head_dic)
    #对需要接收的数据,进行循环接收
    total_size = head_dic['len']  #所需要数据的真实长度
    recv_size = 0
    res = b'' #用来保存所接收的数据
    while recv_size < total_size:
        data = client.recv(1024) #开始接收真实数据,一次最多1024字节
        res += data
        recv_size += len(data)  #记录所接收的数据的长度
    print(res.decode('gbk'))  #将字节类型解码为gbk格式下的字符串


#逻辑正确,可是会报错              问题已解决:彼此间发送接收的数据应该为字节
#json.decoder.JSONDecodeError: Unterminated string starting at: line 1 column 2 (char 1)

  

上述程序的修订版:

#服务端

import socket
import struct
import json
import subprocess

server = socket.socket()
server.bind(('127.0.0.1',8080))
server.listen(5)
while True:
    conn, addr = server.accept()
    while True:
        try:
            data = conn.recv(1024).decode('utf-8')
            obj = subprocess.Popen(data,
                                   shell=True,
                                   stdout=subprocess.PIPE,
                                   stderr=subprocess.PIPE)
            stdout = obj.stdout.read()  #标准输出流
            stderr = obj.stderr.read()  #标准错误流
            print(len(stdout+stderr))
            print('看一下类型',type(stdout))  #<class 'bytes'>
            head_dic = {'filename':'text.py',
                        'len':len(stdout+stderr)}
            #将字典装换为json类型的字节
            header_bytes = json.dumps(head_dic).encode('utf-8')
            #制作报头:
            header = struct.pack('i', len(header_bytes))
            #发送报头
            conn.send(header)
            #发送字典
            conn.send(header_bytes)

            '''
            #制作报头
            header = struct.pack('i',len(head_dic))
            #发送报头
            conn.send(header)  #发送的数据应该为字节模式
            #再发字典
            conn.send(json.dumps(head_dic).encode('utf-8'))
            '''
            #最后发真实数据
            # conn.send((stdout+stderr).encode('utf-8'))
            #stdout本身就是字节类型,因此不需要转码
            conn.send(stdout+stderr)
        except ConnectionResetError:
            break
    conn.close()


#客户端:


import socket
import json
import struct

client = socket.socket()
client.connect(('127.0.0.1',8080))
while True:
    msg = input('>>>:').strip()
    if len(msg) ==0:continue
    client.send(msg.encode('utf-8'))
    #接收报头
    header = client.recv(4)
    #解包报头,获取字典长度
    head_len = struct.unpack('i',header)[0]
    #接收字典
    header_dic = client.recv(head_len)
    #拿到字典里的信息
    header_dic = json.loads(header_dic.decode('utf-8'))
    print(header_dic)
    #对需要接受的真实数据,进行循环接收
    total_size = header_dic.get('len')
    recv_size = 0
    res = b''
    while recv_size < total_size:
        data = client.recv(1024)
        res += data
        recv_size += len(data)
    print(res.decode('gbk'))  #此处需要转码为gbk

  

知识点总结:
1、 TCP协议(流式协议,可靠协议,会出现粘包)
                   会将数据量比较小的且时间间隔比较短的数据一次性打包发送给接收端

       UDP协议(数据报协议):
                    不需要建立双向连接,但是传输数据不可靠,可能会存在丢包情况。通信速度快,但是发送的数据不会再内存里保留。


2、socket套接字
    基于socket实现客户端与服务端通信,处在应用层与传输层之间

3、本机回环地址: 127.0.0.1  只能本机访问

4、解决粘包问题的方法:
    
    服务端:
                1、先发报头
                2、再发字典
                3、再发所需要的真实数据

    客户端:
                1、先接受4个长度的报头
                2、解包拿到字典的数据长度
                3、接受字典,需要反序列化,获取字典里所有的信息
                4、接受真实数据

  

原文地址:https://www.cnblogs.com/changwenjun-666/p/10810446.html