原理概述

  上图是我在学习python的socket编程中遇到的黏包问题所画,以实例来说明这个高大上的黏包问题。

  我们知道socket()实例中sendall()方法是无论数据有多大,一次性提交写入缓冲区(应用层);再来看接收端,recv()方法有个参数为buffsize,没错buffsize就是套接口的发送缓冲区的大小了。所以数据大于SO_SNDBUF的就会被分块传输,问题就来了,当两次提交的数据都比较大,刚好第一次尾与第二次的首同一时间待在了SO_SNDBUF里,被接收到了,这就是黏包。

  一句话:黏包最本质的原因就是接收方不知道接收的包有多大!

解决方法(应用层维护消息和消息边界):

  1. 定长包
  2. 包尾加上\r\n标记(FTP)
  3. 包头增加包体长度。
  4. 复杂的应用层协议。

实例

  本实例多线程实例,实现的是客户端向服务端输入系统命令,服务器返回命令在本机上的执行结果。因为有些命令返回的结果是远大于1024的,所以可能出现黏包的问题。本实例的解决方案是第三条,server端每次向client端返回命令执行结果前,先发送包体大小并得到client端返回的确认信息,再发送数据,程序结构上避免了黏包问题。

TCPSocket服务端

#!/usr/bin/env python
#-*- coding:utf-8 -*-
import SocketServer
import os class Myserver(SocketServer.BaseRequestHandler): def handle(self):
conn = self.request
print "Client from:",self.client_address
conn.sendall("请输入您要查询的命令")
flag = True
while flag:
data = conn.recv(1024)
print "receive cmd: %s"%data
if data == "exit":
flag = False
else:
ret = os.popen(data).read().decode("gbk").encode("utf-8")
         #发送包大小
conn.sendall(str(len(ret)))
#收到客户端确认消息。
scOK = conn.recv(1024)
         #发送包体内容
conn.sendall(ret) if __name__ == "__main__":
server = SocketServer.ThreadingTCPServer(("localhost",8000),Myserver)
server.serve_forever()

TCPSocket客户端

#!/usr/bin/env python
#-*- coding:utf-8 -*-
import socket
sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sk.connect(("127.0.0.1",8000))
sk.settimeout(5)
data = sk.recv(1024)
print "SocketServer: %s" % data
while True:
reSize = 0
msg = raw_input("Input:")
sk.sendall(msg)
  #接收包的大小
totleSize = int(sk.recv(1024))
  #收到包的大小后,给server端发送确认信息。
sk.sendall("It is ok")
while True:
data = sk.recv(1024)
reSize += len(data)
    #当接收数据等于包的size后,跳出循环,停止 接收。
if reSize == totleSize:
print data
break
print data
if msg == "exit":
break
sk.close()

 

socket编程之黏包的更多相关文章

  1. python socket编程和黏包问题

    一.基于TCP的socket tcp是基于链接的,必须先启动服务端,然后再启动客户端去链接服务端,有顺序,不重复,可靠.不会被加上数据边界. server端 import socket sk = so ...

  2. Python网络编程基础 ❷ 基于upd的socket服务 TCP黏包现象

    TCP的长连接 基于upd的socket服务 TCP黏包现象

  3. python/socket编程之粘包

    python/socket编程之粘包 粘包 只有TCP有粘包现象,UDP永远不会粘包. 首先需要掌握一个socket收发消息的原理 发送端可以是1k,1k的发送数据而接受端的应用程序可以2k,2k的提 ...

  4. 2、网络并发编程--套接字编程、黏包问题、struct模块、制作简易报头、上传文件数据

    昨日内容回顾 面向对象复习(json序列化类) 对象.类.父类的概念 三大特性:封装 继承 多态 双下开头的方法(达到某个条件自动触发) __init__:对象实例化自动触发 __str__:对象执行 ...

  5. Python网络编程之黏包问题

    二.解决黏包问题 2.1 解决黏包方法1 计算消息实体的大小 服务端接受两次,一次时消息大小,二次是消息实体,解决消息实体黏包 客户端发送两次,一次是消息大小,一次是消息实体 在两次收发之间加入一次多 ...

  6. Python学习笔记【第十四篇】:Python网络编程二黏包问题、socketserver、验证合法性

    TCP/IP网络通讯粘包问题 案例:模拟执行shell命令,服务器返回相应的类容.发送指令的客户端容错率暂无考虑,按照正确的指令发送即可. 服务端代码 # -*- coding: utf- -*- # ...

  7. 《Python》网络编程之黏包

    黏包 一.黏包现象 同时执行多条命令之后,得到的结果很可能只有一部分,在执行其他命令的时候又接收到之前执行的另外一部分结果,这种显现就是黏包. server端 import socket sk = s ...

  8. socket模块和黏包问题

    socket套接字简介 编写cs架构的程序 实现数据交互 OSI七层相当复杂 socket套接字是一门技术 socket模块>>>:提供了快捷方式 不需要自己处理每一层 " ...

  9. 网络编程- 解决黏包现象方案二之struct模块(七)

    上面利用struct模块与方案一比较,减少一次发送和接收请求,因为方案一无法知道client端发送内容的长度到底有多长需要和接收OK.多一次请求防止黏包,减少网络延迟

随机推荐

  1. 【Java基础-实验7】Banking_7 -添加银行透支扣款系统的 thorw异常机制

    实验基本要求: 实验题目 7:(在6基础上修改) 将建立一个 OverdraftException 异常,它由 Account 类的withdraw()方法 抛出. 实验目的: 自定义异常 实验说明: ...

  2. vue-cli3 clone项目后如何安装插件及依赖模块启动项目

    一. 前提条件1.确保使用的是Node 8.11.0+和NPM 3+:2.确保已全局安装vue-clie3:npm install -g @vue/cli: 二.安装依赖 1.在安装依赖之前,先安装官 ...

  3. 转发:i p _ f o r w a r d函数

    转发:i p _ f o r w a r d函数到达非最终目的地系统的分组需要被转发.只有当 i p f o r w a r d i n g非零或当分组中包含源路由时,i p i n t r才调用实现 ...

  4. php基本语法形式

    站长新闻: 备注:目前有很多人通过李书记博客找到我,请教各种关于问题,而我这段时间是比较忙的,有时候真的是有心无力,网站更新也少了,希望大家见谅!还有很多phper希望我找下关于php相关的技术文档我 ...

  5. Vue项目创建build打包后可修改的配置文件

    需要一个配置文件,能在项目打包(build)时不被打包,方便修改,同时项目刷新时读取改配置. 实现方法如下: 1.在项目的static目录下创建project.config.json文件(名称随意,建 ...

  6. HTML的列表,表格与媒体元素

    一.无序列表 <ul>                            <li>无序列表</li>                            &l ...

  7. date/clock/hwclock/cal

    date 显示日期与时间 date +%Y/%m/%d/%H:%M 2018/10/08/17:35 格式化输出 时间的设置 查看时区 date -R 时间戳转化 time1=$(date +%s - ...

  8. Onpaint()函数中绘图出现问题:当多次进入onpaint()发现次数达到一定程度就会出现窗口不能再重绘导致窗口内容损坏的现象

    我在一个按钮中调用sendmessage(wm_paint,0,0)达到36以上时,当最小化窗口然后再恢复就会发现窗口出现错误信息,而且窗口界面内容混乱不完整.原来以为是使用sleep()函数导致的问 ...

  9. win10 下载安装tasm

    下载tasm http://www.technorange.com/wp-content/uploads/Tasm%201.4%20Windows%207-Windows%208%2064%20bit ...

  10. Java主线程在子线程执行完毕后再执行

    一.join() Thread中的join()方法就是同步,它使得线程之间由并行执行变为串行执行. public class MyJoinTest { public static void main( ...