解决socket TCP粘包

  1. 前言
  2. 正文

前言

在socket网络程序中,TCP和UDP分别是面向连接和非面向连接的。因此TCP的socket编程,收发两端(客户端和服务器端)都要有成对的socket,因此,发送端为了将多个发往接收端的包,更有效的发到对方,使用了优化方法(Nagle算法),将多次间隔较小、数据量小的数据,合并成一个大的数据块,然后进行封包。这样,接收端,就难于分辨出来了,必须提供科学的拆包机制。

对于UDP,不会使用块的合并优化算法,这样,实际上目前认为,是由于UDP支持的是一对多的模式,所以接收端的skbuff(套接字缓冲区)采用了链式结构来记录每一个到达的UDP包,在每个UDP包中就有了消息头(消息来源地址,端口等信息),这样,对于接收端来说,就容易进行区分处理了。所以UDP不会出现粘包问题。
220632-15416859924c51.jpg
拔剑神曲βios:

正文

server端:

import socket
import subprocess
import struct
import json

def server(host,port):
    servers=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    servers.bind((host,port))
    servers.listen(1)
    while True:
        shargs,args=servers.accept()
        print('[+] ソースIP:{}'.format(args[0]))

        while True:
            try:
                msg=shargs.recv(1024)
                res=subprocess.Popen(msg.decode('utf-8'),shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
                out_read=res.stdout.read()
                err_read=res.stderr.read()
                data_size=len(out_read)+len(err_read) /获取数据长度
                head_dic={"data_size":data_size} //打包成json
                head_json=json.dumps(head_dic) //为str类型
                head_bytes=head_json.encode('utf-8') //报文编码为utf8
                head_len=len(head_bytes) //报文长度
                shargs.sendall(struct.pack("i",head_len)) //先发送报文长度
                shargs.sendall(head_bytes) //发送报文
                shargs.sendall(out_read) //发送真实数据
                shargs.sendall(err_read)
            except:
                pass
if __name__ == '__main__':
    host='127.0.0.1'
    port=4448
    server(host,port)

client段

import socket
import struct
import json

def client(host,port):
    clients=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    try:
        clients.connect((host,port))
        print('[+] 接続が成功する')
    except:
        print('[-] 接続失敗')
        exit()

    while True:
        user=input('コマンドを入力してください:')
        if not user:
            continue
        clients.sendall(bytes(user,encoding='utf8')) 

        head_rec=clients.recv(4) //读取4个字符
        print('head_rec',head_rec) 
        head_len=struct.unpack("i",head_rec)[0] //解开报文第一个字符为16进制(获取长度)
        print(head_len)

        head_byte=clients.recv(head_len) //读取指定长度的数据
        print('head_byte:',head_byte) 
        head_json=head_byte.decode('utf8') //获取到json并解码为utf8
        head_dic=json.loads(head_json) //解析josn
        data_size=head_dic["data_size"] //得到字节总

        recv_size=0
        recv_data=b''
        while recv_size<data_size: 
            js=clients.recv(1024) //读取数据
            print(js)
            recv_size+=len(js) //字节和返回数据长度加在一起
            print(recv_size)
            print('recv_data:',recv_data) //b''+返回数据
            recv_data+=js
         print(recv_data.decode('utf-8')) //解码为utf-8
    clients.close()

if __name__ == '__main__':
    host='127.0.0.1'
    port=4447
    client(host,port)

转载请声明:转自422926799.github.io


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。

文章标题:解决socket TCP粘包

本文作者:九世

发布时间:2018-11-16, 19:40:24

最后更新:2019-04-19, 20:36:16

原始链接:http://422926799.github.io/posts/ee45ea9a.html

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录