scoket模块 粘包问题 tcp协议特点

scoket()模块函数用法

import socket
socket.socket(socket_family,socket_type,protocal=0)

获取tcp/ip套接字
tcpsock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

获取udp/ip套接字
udpsock =socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

服务端套接字函数

s.bind()      绑定(主机,端口号)到套接字

s.listen()    开始tcp监听

s.accept()  被动接受tcp客户的连接,(阻塞式)等待连接的到来

客户端套接字函数

s.connect()   主动初始化tcp服务器连接

s.connect_ex()  connect()函数的扩展版本,出错时返回出错码,而不是抛出异常

公共用途的套接字函数

s.recv()  接收tcp数据

s.send()  发送tcp数据(send在待发送数据量大于己端缓存区剩余空间时,数据丢失,不会发完)

s.recvfrom()  接收udp数据

s.sendto()   发送udp数据

s.close()    关闭套接字

1 用打电话的流程快速描述socket通信
2 服务端和客户端加上基于一次连接的循环通信
3 客户端发送发空,卡主,证明是从那一个位置卡的

服务端:
from socket import *

phone =socket(AF_INET,SOCK_STREAM)
phone.bind((‘127.0.0.1‘,8081))
phone.listen(5)

conn,addr =phone.accept()
while True:
    data =conn.recv(1024)
    print(‘server===>‘)
    print(data)
    conn.send(data.upper())
conn.close()
phone.close()

客户端:
from socket import *

phone=socket(AF_INET,SOCK_STREAM)
phone.connect((‘127.0.0.1‘,8081))

while True:
    msg=input(‘>>: ‘).strip()
    phone.send(msg.encode(‘utf-8‘))
    print(‘client===>‘)
    data=phone.recv(1024)
    print(data)

说明卡的原有:缓冲区为空recv就卡主,引出原理图

简单演示udp
服务端
from socket import *
phone =socket(AF_INET,SOCK_DGRAM)
phone.bind((‘127.0.0.1‘,8082))

while True:
    msg,addr =phone.recvfrom(1024)
    phone.sendto(msg.upper(),addr)

# 客户端
from socket import *
phone =socket(AF_INET,SOCK_DGRAM)
while True:
    msg=input(‘>>: ‘)
    phone.sendto(msg.encode(‘utf-8‘),(‘127.0.0.1‘,8082))
    msg,addr =phone.recvfrom(1024)
    print(msg)

udp客户端可以并发演示
udp客户端可以输入为空演示

socket 实验推演流程

基于TCP的套接字

  tcp是基于连接的,必须先启动服务端,然后再启动客户端去连接服务端

tcp服务端

from socket import *
ss=socket() #创建服务器套接字
ss.bind()   #把地址绑定到套接字
ss.listen() #监听连接
inf_loop:   #服务器无线循环
    cs=ss.accept()  #接收客户端连接
    comm_loop:      #通信循环
        cs.recv()/cs.send() #对话(接收与发送)
    cs.close()  #关闭客户端套接字
ss.close()      #关闭服务器套接字(可选)

tcp客户端

cs=socket()     #创建客户套接字
cs.connect()    #尝试连接服务器
comm_loop:      #通讯循环
    cs.send()/cs.recv() #对话(发送/接收)
cs.close()      #关闭客户套接字

socket 通信流程与打电话流程类似

基于tcp协议通信的套接字

import socket

server = socket.socket() #买手机
server.bind((‘127.0.0.1‘,8080)) #插手机卡  bind((ip,port))

server.listen(5)  #开机  半整数池

conn , addr =server.accept()  #待机等待接电话
print(conn)  #双向通道
print(addr)  #地址  (‘127.0.0.1‘, 52942)

data = conn.recv(1024)  #接听别人说话 只接收1024个字节 bytes

print(data)   #b‘hello how much?‘
conn.send(b‘hello big baby!‘)  #跟别人说话

conn.close()   #关闭通信连接
server.close()  #关闭服务端

服务端

import socket

#t套接字对象
client = socket.socket()

client.connect((‘127.0.0.1‘,8080))  #找服务器 拨电话

client.send(b‘hello how much?‘)  #给服务器发信息
data = client.recv(1024)    #接收服务器发来的信息
print(data)

client.close()   #关闭客户端

客户端

加上连接循环与通信循环

import socket
ip_port=(‘127.0.0.1‘,8081)#电话卡
BUFSIZE=1024
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #买手机
s.bind(ip_port) #手机插卡
s.listen(5)     #手机待机

while True:                         #新增接收链接循环,可以不停的接电话
    conn,addr=s.accept()            #手机接电话
    # print(conn)
    # print(addr)
    print(‘接到来自%s的电话‘ %addr[0])
    while True:                         #新增通信循环,可以不断的通信,收发消息
        msg=conn.recv(BUFSIZE)             #听消息,听话

        # if len(msg) == 0:break        #如果不加,那么正在链接的客户端突然断开,recv便不再阻塞,死循环发生

        print(msg,type(msg))

        conn.send(msg.upper())          #发消息,说话

    conn.close()                    #挂电话

s.close()                       #手机关机

循环服务端

import socket
ip_port=(‘127.0.0.1‘,8081)
BUFSIZE=1024
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

s.connect_ex(ip_port)           #拨电话

while True:                             #新增通信循环,客户端可以不断发收消息
    msg=input(‘>>: ‘).strip()
    if len(msg) == 0:continue
    s.send(msg.encode(‘utf-8‘))         #发消息,说话(只能发送字节类型)

    feedback=s.recv(BUFSIZE)                           #收消息,听话
    print(feedback.decode(‘utf-8‘))

s.close()                                       #挂电话

循环客户端

tcp协议特点

import socket

server = socket.socket()
server.bind((‘127.0.0.1‘,8808))

server.listen(5)  #半连接池 等待连接的最大的客户端数

conn,addr = server.accept()

# data = conn.recv(1024)
# print(data)
 #b‘hellohellohello‘ 接收的小于1024的 所有的客户端发来的信息

data = conn.recv(4)
print(data)
  #b‘hell‘

data = conn.recv(5)
print(data)
 #b‘ohell‘   #会先接收上次没接收完的信息

data = conn.recv(5)
print(data)
 #b‘ohell‘   #会先接收上次没接收完的信息
conn.close()

server.close()

服务端

import socket

client = socket.socket()

client.connect((‘127.0.0.1‘,8808))

client.send(b‘hello‘)
client.send(b‘hello‘)
client.send(b‘hello‘)
#tcp协议的优化特点 发送数据量小的间隔时间短 会一起发送
#会将数据量比较小的并且时间间隔比较短的数据一次性打包发送给接收端

client.close()

客户端

struct模块

import  struct

data=‘sdkjfksdfjsdkfjksdjfkjdsk‘

#服务端
res = struct.pack(‘i‘,len(data))

print(len(res))  #4 会把多个字符的字符串 打包成只有4个的对象

print(res)  #b‘\x19\x00\x00\x00‘

#客户端
ret=struct.unpack(‘i‘,res)  #解包成原来的 字符串个数 i 代表int 整形
print(ret)   #(25,)
print(ret[0])  #25

模拟ssh实现远程执行命令

import socket
import subprocess
import struct
import json

server =socket.socket()
server.bind((‘127.0.0.1‘,8081))
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(stderr+stdout))

            header_dic = {
                ‘filename‘:‘cls.av‘,
                ‘len‘:len(stdout+stderr)
            }

            header_bytes = json.dumps(header_dic).encode(‘utf-8‘)

            #制作报头
            header = struct.pack(‘i‘,len(header_bytes))

            conn.send(header)
            conn.send(header_bytes)

            conn.send(stdout)
            conn.send(stderr)
                #conn.send(stdout+stderr) 字符串拼接 从新拷贝一份占内存
                #  和单独发也是一样的 间隔时间短的接收到的也是一起的
        except  ConnectionResetError:
            break

    conn.close()
server.close()

服务端

import socket,struct,json

client = socket.socket()

client.connect((‘127.0.0.1‘,8081))

while True:
    msg = input(‘>>>: ‘).encode(‘utf-8‘)
    if len(msg)==0:continue

    client.send(msg)

    header = client.recv(4)  #接收字典打包后的4个长度的字节 精确接收
    print(header,‘这是报头的长度‘)

    head_len = struct.unpack(‘i‘,header)[0] #对这个头进行解包,获取原来的字典的字节数长度
    print(head_len,‘这是字典的字节数‘)

    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)  #每次接收到的信息
        res +=data
        recv_size +=len(data)
    print(res.decode(‘gbk‘))

client.close()

客户端

udp套接字

udp是无连接的,先启动那一端都不会报错

udp服务端

 ss=socket()    #创建一个服务器的套接字
 ss.bind()        #绑定服务器套接字
 inf_loop:         #服务器无限循环
    cs=ss.recvfrom()/ss.sendto()    #对话(接收与发送)
 ss.close()        #关闭服务器套接字

udp客户端

cs=socket()        #创建客户端套接字
comm_loop:        #通信循环
    cs.sendto()/cs.recvfrom()        #对话(发送/接收)
cs.close()            #关闭客户套接字

udp套接字简单实例

服务端
import socket

server = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
server.bind((‘127.0.0.1‘,8080))

while True:
    data ,addr =server.recvfrom(1024)
    print(data)

    server.sendto(data.upper(),addr)
客户端
import socket

client = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
server_addr=(‘127.0.0.1‘,8080)  #服务端地址,通常写在配置文件中

client.sendto(b‘hello‘,server_addr)

udp 实现简易版本的qq

import socket
server=socket.socket(type=socket.SOCK_DGRAM)
server.bind((‘127.0.0.1‘,8080))

while True:
    msg,addr =server.recvfrom(1024)
    print(addr,msg.decode(‘utf-8‘))
    data=input(‘服务端回复:‘).encode(‘utf-8‘)
    server.sendto(data,addr)

服务端

import socket

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

server_addr =(‘127.0.0.1‘,8080)

while True:
    msg = input(‘输入消息:‘)
    msg = ‘客服端1的消息:%s‘ % msg
    client.sendto(msg.encode(‘utf-8‘),server_addr)
    data,addr =client.recvfrom(1024)
    print(data.decode(‘utf-8‘))

客户端

import socket

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

server_addr =(‘127.0.0.1‘,8080)

while True:
    msg = input(‘输入消息:‘)
    msg = ‘客服端2的消息:%s‘ % msg
    client.sendto(msg.encode(‘utf-8‘),server_addr)
    data,addr =client.recvfrom(1024)
    print(data.decode(‘utf-8‘))

客户端2

import socket

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

server_addr =(‘127.0.0.1‘,8080)

while True:
    msg=input(‘输入消息:‘)
    msg=‘客服端3的消息:%s‘%msg
    client.sendto(msg.encode(‘utf-8‘),server_addr)
    data,addr =client.recvfrom(1024)
    print(data.decode(‘utf-8‘))

客户端3

subprocess模块

import socket
import subprocess
import struct

‘‘‘
服务端必备三要素:
    1 要有固定的ip和port
    2 要能24小时提供服务
    3 能承受高并发
        并发:看上去像同时进行
‘‘‘
server=socket.socket()
server.bind((‘127.0.0.1‘,8080))
server.listen(5)

while True:
    conn,addr =server.accept()
    while True:
        try:
            cmd =conn.recv(1024).decode(‘utf-8‘)
            if len(cmd)==0:break #针对linux mac系统
            obj=subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)

            stdout=obj.stdout.read()
            stderr=obj.stderr.read()

            #制作固定报头
            header=struct.pack(‘i‘,len(stderr+stdout))
            #发送固定长度的报头
            conn.send(header)

            #发送真是数据
            conn.send(stdout)
            conn.send(stderr)
        except ConnectionResetError:
            break
    conn.close()

服务端

import socket
import struct

client =socket.socket()
client.connect((‘127.0.0.1‘,8080))

while True:
    cmd =input(‘>>:‘).encode(‘utf-8‘)
    if len(cmd)==0:continue
    client.send(cmd)

    header=client.recv(4)
    #解析报头获取真是数据的长度
    total_size=struct.unpack(‘i‘,header)[0]
    recv_size=0
    data=b""
    while recv_size<total_size:
        res=client.recv(1024)
        recv_size+=len(res)
        data+=res

    print(data.decode(‘gbk‘))

客户端

socketserver模块 实现并发  基于tcp的套接字,关键字就是两个循环,一个是连接循环,一个通信循环

socketserver模块中分两大类:server类(解决连接问题)和request类(解决通信问题)

基于tcp的socketserver自定义的类中的

  1 self.server即套接字对象

  2 self.request即一个连接

  3 self.client_address即客户端地址

基于udp的socketserver自定义的类中的

  1 self.request是一个元组(第一个元素是客户端发来的数据,第二部分是服务端的udp套接字对象),

  如(b‘adsf‘, <socket.socket fd=200, family=AddressFamily.AF_INET, type=SocketKind.SOCK_DGRAM, proto=0, laddr=(‘127.0.0.1‘, 8080)>)

  2 self.client_address即客户端地址

import socket

client =socket.socket()
client.connect((‘127.0.0.1‘,8080))

while True:
    client.send(b‘hello world‘)
    data= client.recv(1024)

    print(data)

tcp客户端

import socketserver

class MyBaby(socketserver.BaseRequestHandler):
    def handle(self):
        #通信循环
        while True:
            #self.request相当于你的conn通信对象
            data= self.request.recv(1024) #收消息
            print(data)
            self.request.send(data.upper())

if __name__ == ‘__main__‘:          #通道循环
    server = socketserver.ThreadingTCPServer((‘127.0.0.1‘,8080),MyBaby)
    server.serve_forever()

tcp服务端

import  socket
import time

client =socket.socket(type=socket.SOCK_DGRAM)
server_addr=(‘127.0.0.1‘,8080)

while True:
    client.sendto(b‘hello world‘,server_addr)
    data,addr =client.recvfrom(1024)
    print(data,addr)
    time.sleep(1)

udp客户端

import socketserver

class MyBaby(socketserver.BaseRequestHandler):
    def handle(self):
        #通讯循环
        while True:
            #self.request 相当于conn通讯对象
            data,sock =self.request #收消息
            print(data)
            print(sock)
            sock.sendto(data.upper(),self.client_address)  #self.client_address 客户端地址

if __name__ == ‘__main__‘:
    server=socketserver.ThreadingUDPServer((‘127.0.0.1‘,8080),MyBaby)
    server.serve_forever()

udp服务端

基于tcp文件上传

import socket
import struct
import json

server = socket.socket()
server.bind((‘127.0.0.1‘, 8080))
server.listen(5)

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

    while True:
        try:
            # 接收报头
            header = conn.recv(4)
            # 解析报头获取字典长度
            header_len = struct.unpack(‘i‘, header)[0]

            # 接收字典
            header_bytes = conn.recv(header_len)
            header_dic = json.loads(header_bytes.decode(‘utf-8‘))
            print(header_dic)

            # 循环接收文件存储到本地
            file_size = header_dic.get(‘file_size‘)
            file_name = header_dic.get(‘file_name‘)

            recv_size = 0
            # 文件操作
            with open(file_name, ‘wb‘)as f:
                # 循环接收文件
                while recv_size < file_size:
                    data = conn.recv(1024)
                    f.write(data)
                    recv_size += len(data)
            print(header_dic.get(‘msg‘))
        except ConnectionResetError:
            break
    conn.close()

服务端

import socket
import os
import json
import struct

client = socket.socket()
client.connect((‘127.0.0.1‘, 8080))

# 文件大小
file_size = os.path.getsize(r‘E:\代码存放位置\第八周\莫文蔚-偷情.mp3‘)

# 文件名字
file_name = ‘歌曲名:偷情- 歌手:莫文蔚.mp3‘

# 定义一个字典
d = {
    "file_name": file_name,
    "file_size": file_size,
    "msg": ‘注意身体哦‘

}

data_bytes = json.dumps(d).encode(‘utf-8‘)

# 制作字典的报头
header = struct.pack(‘i‘, len(data_bytes))

# 发送报头
client.send(header)

# 发送字典
client.send(data_bytes)

# 发送真实数据
with open(r‘E:\代码存放位置\第八周\莫文蔚-偷情.mp3‘, ‘rb‘)as f:
    for line in f:
        client.send(line)

客户端

import json

res = {‘name‘: ‘他说大帅比‘}
# print(json.dumps(res,ensure_ascii=False)) #{"name": "他说大帅比"}
print(json.dumps(res))  # {"name": "\u4ed6\u8bf4\u5927\u5e05\u6bd4"}

‘‘‘

    TCP
        三次握手
        可靠协议,流式协议

    粘包问题的产生:
        1.接收方:
            我不知道我要接受的数据的总长度
        2.发送方:
            由于TCP协议的内部优化算法negle
            1.会将数据量比较的小的并且时间间隔比较短的数据一次性打包发送

    UDP
    数据报协议
    没有双向通道

    1.UDP协议不存在粘包问题
    2.客户端可以发空
    3.udp可以实现并发的效果
    4.服务端不存在,也不影响客户端朝服务端发送数据

    TCP/UDP
        TCP:打电话
        UDP:发短信

SocketServer模块
    1.能够实现并发效果
        并发:看起来像同时运行就能称之位并发

    2.udp在使用的时候,多个客户端要有一些io操作
        不然容易卡死

并发编程
    操作系统发展史

    多道技术:
        - 空间上的复用(多个程序共一套硬件设备,它是多道技术实现时间上的复用的基础,
            不然还要去硬盘读数据)

        - 时间上的复用(单个cpu的电脑上,起多个应用程序。cpu快速切换,给人的感觉是同时运行)

        cpu两种情况下才会切换:(先保存当前程序的运行状态)
            - 一个任务占用cpu时间过长或被操作系统强行剥夺走cpu的执行权限(比起串行效率反而降低)
            - 一个任务执行过程中遇到io操作,也会被操作系统强行剥夺走cpu的执行权限(比起串行效率提高)

    并发:看上去像同时进行的
    并行:同时运行
    补充:单核的计算机不可能实现并行!
    ‘‘‘

原文地址:https://www.cnblogs.com/lakei/p/10797396.html

时间: 2024-08-01 05:24:00

scoket模块 粘包问题 tcp协议特点的相关文章

闲说HeartBeat心跳包和TCP协议的KeepAlive机制

很多应用层协议都有HeartBeat机制,通常是客户端每隔一小段时间向服务器发送一个数据包,通知服务器自己仍然在线,并传输一些可能必要的数据.使用心跳包的典型协议是IM,比如QQ/MSN/飞信等协议. 学过TCP/IP的同学应该都知道,传输层的两个主要协议是UDP和TCP,其中UDP是无连接的.面向packet的,而TCP协议是有连接.面向流的协议. 所以非常容易理解,使用UDP协议的客户端(例如早期的“OICQ”,听说OICQ.com这两天被抢注了来着,好古老的回忆)需要定时向服务器发送心跳包

第六章 - 网络编程 - 粘包

1.粘包: 多个包 多个命令的结果 粘到一起了 因为recv 1024限制了 导致的结果 参考:http://www.cnblogs.com/linhaifeng/articles/6129246.html 粘包底层原理分析: 1.运行一个软件 和 哪几个硬件 有关 硬盘 内存 cpu 2.启动程序: 硬盘程序 加载到 内存 启一个软件就占一个内存空间 os 就有一个内存空间 os的内存空间 和 软件的内存空间 彼此互相隔离 须知:只有TCP有粘包现象,UDP永远不会粘包. 所谓粘包问题主要还是

No.29粘包

No.29 今日概要 粘包问题 内容回顾 OSI七层协议 应用层 传输层(理解port) tcp 可靠.慢.全双工.数据长度大 三次握手:发了 syn/ack 信号 三次握手把一个回复和请求连接的两条信息合并成一条了 四次挥手:发了 fin/ack 信号 由于一方断开连接后,可能另一方还有数据没有传递完,所以不能立即断开. udp 不可靠.快.数据长度小 四层路由器.四层交换机 网络层(理解ip) ipv4 / ipv6 路由器.三层交换机 数据链路层(理解mac) arp协议 交换机.网卡 物

socket 的粘包问题解决方案

粘包: 由于接受recv有最大限制,管道中有大于最大限制字节时, 第二次recv的会是之前残留的信息,这种现象叫做粘包. TCP协议是面向连接的,面向流的,当在发送数据时接受方不知道要收多少字节的数据,但由于缓存区大小的限制,我们又不可能设置很大的接受量,这时便需要有一个解决方案,避免产生粘包的现象. 解决方案:明确地告知接收端要收多大的数据,在开始循环的接受数据 实例: 原文地址:https://www.cnblogs.com/captain08/p/9074416.html

TCP粘包/拆包问题

无论是服务端还是客户端,当我们读取或者发送消息的时候,都需要考虑TCP底层的粘包/拆包机制. TCP粘包/拆包 TCP是个"流"协议,所谓流,就是没有界限的一串数据.大家可以想想河里的流水,是连成一片的,其间并没有分界线.TCP底层并不了解上层业务数据的具体含义,它会根据TCP缓冲区的实际情况进行包的划分,所以在业务上认为,一个完整的包可能会被TCP拆分成多个包进行发送,也有可能把多个小的包封装成一个大的数据包发送,这就是所谓的TCP粘包和拆包问题. TCP粘包/拆包问题说明 假设客户

粘包产生的原因 socket 基于tcp实现远程执行命令(解决粘包)low

# 粘包产生的原因 # 粘包问题主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的. # 基于tcp协议的套接字会有粘包现象,而基于udp协议的套接字不会产生粘包现象 # tcp是基于数据流的,于是收发的消息不能为空,这就需要在客户端和服务端都添加空消息的处理机制,防止程序卡住:而udp是基于数据报的,即使你输入的是空内容,那也不是空消息,udp协议会帮你封装上消息头(ip+端口的方式),这样就有了消息办界 # 两种情况下会发生粘包 # 1.发送端需要等缓冲区满才发送

浅析C#基于TCP协议的SCOKET通信

TCP协议是一个基本的网络协议,基本上所有的网络服务都是基于TCP协议的,如HTTP,FTP等等,所以要了解网络编程就必须了解基于TCP协议的编程.然而TCP协议是一个庞杂的体系,要彻底的弄清楚它的实现不是一天两天的功夫,所幸的是在.net framework环境下,我们不必要去追究TCP协议底层的实现,一样可以很方便的编写出基于TCP协议进行网络通讯的程序. C#基于TCP协议的网络通讯 要进行C#基于TCP协议的网络通讯,首先必须建立同远程主机的连接,连接地址通常包括两部分--主机名和端口,

python/socket编程之粘包

python/socket编程之粘包 粘包: 只有TCP有尿包现象,UDP永远不会粘包. 首先需要掌握一个socket收发消息的原理 发送端可以是1k,1k的发送数据而接受端的应用程序可以2k,2k的提取数据,当然也有可能是3k或者多k提取数据,也就是说,应用程序是不可见的,因此TCP协议是面来那个流的协议,这也是容易出现粘包的原因而UDP是面向笑死的协议,每个UDP段都是一条消息,应用程序必须以消息为单位提取数据,不能一次提取任一字节的数据,这一点和TCP是很同的.怎样定义消息呢?认为对方一次

socket之粘包

什么是粘包 粘包是一种现象  这种现象只出现在TCP中而不会出现在UDP中(TCP和UDP都是传输层中的协议) 粘包:粘包问题主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的 粘包概念详解: 当发送网络数据时,tcp协议会根据Nagle算法将时间间隔短,数据量小的多个数据包打包成一个数据包,先发送到自己操作系统的缓存中,然后操作系统将数据包发送到目标程序所对应操作系统的缓存中,最后将目标程序从缓存中取出,而第一个数据包的长度,应用程序并不知道,所以会直接取出数据或者