博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
半连接与粘包问题
阅读量:6240 次
发布时间:2019-06-22

本文共 2972 字,大约阅读时间需要 9 分钟。

半连接数

1、定义:

  三次握手没有完成的称之为半连接数

2、产生半连接的原因:

  1)恶意客户端故意不返回第三次握手信息,服务器就处于time_wait状态

      洪水攻击用的就是这种原理

  2)服务器没有时间处理你的握手请求

3、最大半连接数

  在socket语法中listen()函数的括号中指定的就是最大半连接数

  最大半连接数指的是同一时间接收请求的最大数目,超过的请求会被直接拒绝

粘包问题

粘包问题只存在于TCP协议中,TCP协议又称为流式协议,数据之间是没有分隔的(只能用数据的长度来分隔他们)

1、粘包的定义

  如果一次读取指定缓存区的内容大于或者小于真实数据的大小,就被定义被粘包

2、粘包产生的原因

  发送端和接收端都会造成数据的粘包问题

  --发送端

    1)发送的数据小,并且时间间隔短时,tcp会根据negal优化算法把这两个数据一起发送,会粘

  --接收端

    1)接收端一次性读取了两次的数据内容,会粘

    2)接收端一次没有把数据接收完整,剩余内容和下次发送的也会粘在一起

3、粘包的解决方案

  无论时哪种情况,其根本的原因都在于接收端不知道应该接收多少数据,所以解决的方案就是先把数据长度发给接收端

  --发送端

    1)使用struct将真实数据的长度转换成固定的字节数据

    2)发送长度数据

    3)发送真实数据

import socketimport structclient = socket.socket()client.connect(('127.0.0.1',8080))while True:    data = '巴拉巴拉一大堆数据'.encode('utf-8')    data_len = struct.pack('q',len(data))  # 把数据长度转成固定字节数    client.send(data_len)   # 先发送固定字节数 'q'模式的字节数是8    client.send(data)   # 再发送真实的数据

  --接收端

    1)先收长度数据  字节数固定

    2)再收真实数据 ,真实可能很长,需要循环接收

import socketimport structserver = socket.socket()server.bind(('127.0.0.1',8080))server.listen()while True:    client,addr = server.accept()    while True:        data_len_bytes = client.recv(8) # 先接收传过来的数据长度信息的固定字节'q'模式是8        if not data_len_bytes:            break        data_len = struct.unpack('q',data_len_bytes)[0] # 把接收到的二进制转成数据的长度,返回一个元组,取0号位        data = client.recv(data_len) # 再根据长度来接收数据(循环接收请看前面)

 

自定义报头

1、需要原因

  有时候我们除了需要把数据的长度告诉接收方,还需要把一些其他信息也告诉接收方,例如我们下载文件,

  服务器就需要把文件名也给我们传过来,这样就需要我们自定义报头

2、报头形式

  当我们想把数据的其他信息传给对面的时候,字典是我们最好的选择

  对面和你的平台可能不一样,这样我们就需要json格式来传输数据,所以报头的本质就是json数据

  想把json数据发过去,又需要先把json数据的长度发过去,真实数据的信息都保存在json数据中

3、有了报头之后的发送流程

  --发送端

    1)发送报头长度

    2)发送报头数据   其中包含了真实文件的长度和其他的任意额外信息

    3)发送真实文件内容

import socket,struct,jsonclient = socket.socket()client.connect(('127.0.0.1',8080))while True:    data = "我是一个很大的文件,并且对面要根据我的名字保存"    # 先写出报头信息    head_info = {
"name":"xxx","size":10000} # 把报头信息转换成json格式 json_head = json.dumps(head_info) # 把json格式的报头信息的二进制长度转换成固定字节 json_head_lens = struct.pack('q',len(json_head.encode('utf-8'))) # 发送固定字节,让多方知道该以多少长度接收报头信息 client.send(json_head_lens) # 发送报头信息,里面包含接下来要发送的真实数据的大小以及名字等等 client.send(json_head.encode('utf-8')) # 发送真实数据 client.send(data.encode('utf-8'))

  --接收端

    1)接收报头长度

    2)接收报头信息

    3)接收文件内容

import socketimport structimport jsonserver = socket.socket()server.bind(('127.0.0.1',8080))server.listen()while True:    client,addr = server.accept()    while True:        head_len_bytes = client.recv(8)        # 先把固定字节数的报头长度接收过来        if not head_len_bytes:            break        head_len = struct.unpack('q',head_len_bytes)[0]        # 转换成报头的长度数据        json_str = client.recv(head_len).decode('utf-8')        # 接收报头的信息,传过来的是json格式        head_info = json.loads(json_str)        # 转成字典格式,方便取值        #head_info = {"name":"xxx","size":10000}        file_size = head_info.get("size")        # 从字典中取出真实文件的大小,根据大小取值,循环取值请看之前的        data = client.recv(file_size)

转载于:https://www.cnblogs.com/hesujian/p/10947099.html

你可能感兴趣的文章
我的友情链接
查看>>
以太坊中的nonce是什么
查看>>
我的友情链接
查看>>
14-9-11 C/C++课程设计--图书馆管理系---<time.h>中时间数据类型的学习记录
查看>>
java环境配置--转载
查看>>
IPAD2 开启手势教程、未越狱
查看>>
WINTEL平板X86国内上市,神舟老总:ipad仅是玩具
查看>>
debian 中文美化
查看>>
实现查询条件文本框、下拉表、复选框页面组装
查看>>
我的友情链接
查看>>
安卓开发中控制台启动adb,总是说adb server is out of date. killing...
查看>>
解决局域网内打印机经常无法正常连接
查看>>
jboss架构
查看>>
2011年上半年(5月份)信息系统监理师考试上午试题参考答案
查看>>
myeclipse6.5安装svn的三种方法!
查看>>
WIN2012 TCP ECN 启用导致速度慢
查看>>
golang多核陷阱一例
查看>>
攻略:苹果手机投屏电脑 iPhone镜像投屏怎么操作
查看>>
机器学习的前世今生:一段波澜壮阔的历史
查看>>
二级菜单
查看>>