内容回顾

osi五层协议

  • 不是真实存在的,只是抽象出来的模型
  • 应用层
  • 传输层 TCP/UDP
    • TCP :全双工,可靠的,面向连接的,速度慢,对数据大小没有限制

      • 建立连接 :三次握手 SYN ACK
      • 断开连接 :四次挥手 FIN ACK
    • UDP :不可靠,无连接的,速度快,对数据大小有限制
  • 网络层 arp(ip-->mac) rarp(mac-->ip)
  • 数据链路层 arp(ip-->mac) rarp(mac-->ip)
  • 物理层 网线

TCP/IP 也是抽象出来的模型

struct 模块

import struct

ret = struct.pack('i',112849)
print(ret)

ret2 = struct.unpack('i',ret)
print(ret2)

总结

  1. 黏包现象 发送的两条数据粘在一起了
  2. 成因 :
    • 发送端粘 : 合包机制
    • 接收端粘 : 接收不及时
    • 数据与数据之间是无边界的流式传输
  3. 解决黏包现象
    • 自定义协议

      • struct模块

        • 把任意长度的数字变成固定的4个字节
      • 低级
        • 先发送数据的长度
        • 再发送数据
      • 高级
        • 先把所有想发送的数据信息放在字典里
        • 发送字典的长度
        • 发送字典
        • 发送涉及的数据
          ##作业:
  4. 默写 黏包协议
  5. 上传大文件(文件\视频\图片)
  6. 和你的同桌调通 从你的计算机上传一个视频到你同桌的电脑上
  7. 进阶 : 带上登录

课上代码

登陆一

server:

import sys
import json
import socket
import hashlib

def get_md5(username,password):
    md5 = hashlib.md5(username.encode('utf-8'))
    md5.update(password.encode('utf-8'))
    return md5.hexdigest()

def login(dic_msg):
    print(dic_msg['user'], dic_msg['pwd'])
    with open('userinfo', encoding='utf-8') as f:
        for line in f:
            user, pwd = line.strip().split('|')
            if user == dic_msg['user'] and pwd == get_md5(dic_msg['user'], dic_msg['pwd']):
                return {'opt':'login','result':True}
        else:return {'opt':'login','result':False}

sk= socket.socket()
sk.bind(('127.0.0.1',9001))
sk.listen()
while True:
    conn,addr = sk.accept()
    msg = conn.recv(1024).decode('utf-8')
    dic_msg = json.loads(msg)
    if hasattr(sys.modules[__name__],dic_msg['operate']):
        ret = getattr(sys.modules[__name__],dic_msg['operate'])(dic_msg)
        content = json.dumps(ret).encode('utf-8')
        conn.send(content)
    conn.close()
sk.close()

Client

import json
import socket

username = input('用户名 :')
password = input('密  码 :')
sk = socket.socket()
sk.connect(('127.0.0.1',9001))
msg = {'operate':'login',
       'user':username,
       'pwd':password}
str_msg = json.dumps(msg)
sk.send(str_msg.encode('utf-8'))
content = sk.recv(1024)
str_content = content.decode('utf-8')
dic_content = json.loads(str_content)
if dic_content['result']:
    print('登录成功')
else:
    print('登录失败')
sk.close()

登陆二

Server

import sys
import json
import socket
import hashlib

def get_md5(username,password):
    md5 = hashlib.md5(username.encode('utf-8'))
    md5.update(password.encode('utf-8'))
    return md5.hexdigest()

def login(dic_msg):
    print(dic_msg['user'], dic_msg['pwd'])
    with open('userinfo', encoding='utf-8') as f:
        for line in f:
            user, pwd = line.strip().split('|')
            print(pwd,get_md5(dic_msg['user'], dic_msg['pwd']))
            if user == dic_msg['user'] and pwd == get_md5(dic_msg['user'], dic_msg['pwd']):
                return {'opt':'login','result':True}
        else:return {'opt':'login','result':False}

sk= socket.socket()
sk.bind(('127.0.0.1',9001))
sk.listen()
while True:
    conn,addr = sk.accept()
    msg = conn.recv(1024).decode('utf-8')
    dic_msg = json.loads(msg)
    if hasattr(sys.modules[__name__],dic_msg['operate']):
        ret = getattr(sys.modules[__name__],dic_msg['operate'])(dic_msg)
        content = json.dumps(ret).encode('utf-8')
        conn.send(content)
    conn.close()
sk.close()

Client

import json
import socket
import hashlib

def get_md5(username,password):
    md5 = hashlib.md5(username[::2].encode('utf-8'))
    md5.update(password.encode('utf-8'))
    return md5.hexdigest()
username = input('用户名 :')
password = input('密  码 :')
sk = socket.socket()
sk.connect(('127.0.0.1',9001))
msg = {'operate':'login',
       'user':username,
       'pwd':get_md5(username,password)}
str_msg = json.dumps(msg)
sk.send(str_msg.encode('utf-8'))
content = sk.recv(1024)
str_content = content.decode('utf-8')
dic_content = json.loads(str_content)
if dic_content['result']:
    print('登录成功')
else:
    print('登录失败')
sk.close()

黏包练习

Server

import struct
import socket

sk = socket.socket()
sk.bind(('127.0.0.1',9001))
sk.listen()

conn,addr = sk.accept()
num = conn.recv(4)
num = struct.unpack('i',num)[0]
file_name = conn.recv(num).decode('utf-8')
filesize = conn.recv(4)
filesize = struct.unpack('i',filesize)[0]
with open(file_name,'wb') as f:
    content = conn.recv(filesize)
    f.write(content)

conn.close()
sk.close()

Client

import os
import struct
import socket

sk = socket.socket()
sk.connect(('127.0.0.1',9001))

filepath  = input('请输入文件路径 :')
filename = os.path.basename(filepath).encode('utf-8')
name_len = struct.pack('i',len(filename))
sk.send(name_len)
sk.send(filename)
filesize = os.path.getsize(filepath)
file_len = struct.pack('i',filesize)
sk.send(file_len)
with open(filepath,'rb') as f:
    content = f.read()
    sk.send(content)
sk.close()

# 先发送字典的长度
# 再发字典 {'filename':xxxx,'filesize':xxxxx}
# 再发文件内容

黏包现象

Server

import socket

sk = socket.socket()
sk.bind(('127.0.0.1',9001))
sk.listen()

conn,addr = sk.accept()
conn.send(b'0015hello,你好么')
conn.send(b'5world')
conn.close()

sk.close()

Client

import time
import socket

sk = socket.socket()
sk.connect(('127.0.0.1',9001))

time.sleep(0.1)
num= sk.recv(2).decode('utf-8')
num = int(num)
msg1 = sk.recv(num)
num= sk.recv(1).decode('utf-8')
num = int(num)
msg2 = sk.recv(num)
print(msg1,msg2)
sk.close()

黏包现象2

Server

import struct
import socket

sk = socket.socket()
sk.bind(('127.0.0.1',9001))
sk.listen()

conn,addr = sk.accept()
str_msg = 'hello,你好么'
byets_msg = str_msg.encode('utf-8')
num = len(byets_msg)
len_bytes = struct.pack('i',num)
conn.send(len_bytes)
conn.send(byets_msg)
conn.send(b'world')
conn.close()

sk.close()

Client

import time
import struct
import socket

sk = socket.socket()
sk.connect(('127.0.0.1',9001))

time.sleep(0.1)
num= sk.recv(4)
num = struct.unpack('i',num)[0]
msg2 = sk.recv(num)
print(msg2.decode('utf-8'))
print(sk.recv(1024))

sk.close()

黏包协议

Server

import json
import struct
import socket

sk = socket.socket()
sk.bind(('127.0.0.1',9001))
sk.listen()

conn,addr = sk.accept()
num = conn.recv(4)
num = struct.unpack('i',num)[0]
str_dic = conn.recv(num).decode('utf-8')
dic = json.loads(str_dic)
with open(dic['filename'],'wb') as f:
    content = conn.recv(dic['filesize'])
    f.write(content)

conn.close()
sk.close()

Client

import os
import json
import struct
import socket

sk = socket.socket()
sk.connect(('127.0.0.1',9001))

filepath  = input('请输入文件路径 :')
filename = os.path.basename(filepath)
filesize = os.path.getsize(filepath)
dic = {'filename':filename,'filesize':filesize}
str_dic = json.dumps(dic)
bytes_dic = str_dic.encode('utf-8')
len_dic = len(bytes_dic)
bytes_len = struct.pack('i',len_dic)
sk.send(bytes_len)
sk.send(bytes_dic)
with open(filepath,'rb') as f:
    content = f.read()
    sk.send(content)
sk.close()

# 先发送字典的长度
# 再发字典 {'filename':xxxx,'filesize':xxxxx}
# 再发文件内容

一对多人聊天

Server

import json
import socket

sk = socket.socket(type=socket.SOCK_DGRAM)
sk.bind(('127.0.0.1',9001))
user_info = {
    1234:('alex','\033[1;32m'),
    5678:('宝元','\033[1;31m'),
}
while True:
    msg,addr = sk.recvfrom(1024)
    str_msg = msg.decode('utf-8')
    dic_msg = json.loads(str_msg)
    code = dic_msg['code']
    content = dic_msg['msg']
    print('%s%s : %s\033[0m'%(user_info[code][1],user_info[code][0],content))
    ret = input('>>>').encode('utf-8')
    sk.sendto(ret,addr)
sk.close()

ClientI

import json
import socket

sk = socket.socket(type=socket.SOCK_DGRAM)
addr = ('127.0.0.1',9001)
code = 5678
while True:
    msg = input('>>>')
    if msg.upper() == 'Q': break
    send_msg = {'code':code,'msg':msg}
    str_msg = json.dumps(send_msg)
    sk.sendto(str_msg.encode('utf-8'),addr)
    ret = sk.recv(1024).decode('utf-8')
    if ret.upper() == 'Q': break
    print(ret)
sk.close()

ClientII

import json
import socket

sk = socket.socket(type=socket.SOCK_DGRAM)
addr = ('127.0.0.1',9001)
code = 1234
while True:
    msg = input('>>>')
    if msg.upper() == 'Q':break
    send_msg = {'code':code,'msg':msg}
    str_msg = json.dumps(send_msg)
    sk.sendto(str_msg.encode('utf-8'),addr)
    ret = sk.recv(1024).decode('utf-8')
    if ret.upper() == 'Q':break
    print(ret)
sk.close()

2019-04-10-day029-粘包处理的更多相关文章

  1. 2019.04.10打卡(HTML)

    代码 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.o ...

  2. Python网络编程04 /recv工作原理、展示收发问题、粘包现象

    Python网络编程04 /recv工作原理.展示收发问题.粘包现象 目录 Python网络编程04 /recv工作原理.展示收发问题.粘包现象 1. recv工作原理 2. 展示收发问题示例 发多次 ...

  3. TCP粘包拆包问题

    阿π 专注于网络协议,系统底层,服务器软件 C++博客 | 首页 | 发新随笔 | 发新文章 | | | 管理 Socket粘包问题 这两天看csdn有一些关于socket粘包,socket缓冲区设置 ...

  4. 基于tcp协议下粘包现象和解决方案,socketserver

    一.缓冲区 每个 socket 被创建后,都会分配两个缓冲区,输入缓冲区和输出缓冲区.write()/send() 并不立即向网络中传输数据,而是先将数据写入缓冲区中,再由TCP协议将数据从缓冲区发送 ...

  5. Socket/TCP粘包、多包和少包, 断包

    转发: https://blog.csdn.net/pi9nc/article/details/17165171 为什么TCP 会粘包 前几天,调试mina的TCP通信, 第一个协议包解析正常,第二个 ...

  6. Socket粘包问题

    这两天看csdn有一些关于socket粘包,socket缓冲区设置的问题,发现自己不是很清楚,所以查资料了解记录一下: 一两个简单概念长连接与短连接:1.长连接 Client方与Server方先建立通 ...

  7. netty 解决TCP粘包与拆包问题(一)

    1.什么是TCP粘包与拆包 首先TCP是一个"流"协议,犹如河中水一样连成一片,没有严格的分界线.当我们在发送数据的时候就会出现多发送与少发送问题,也就是TCP粘包与拆包.得不到我 ...

  8. TCP拆包粘包之分隔符解码器

    TCP以流的方式进行数据传输,上层的应用协议为了对消息进行区分,往往采用如下4种方式. (1)消息长度固定,累计读取到长度总和为定长LEN的报文后,就认为读取到了一个完整的消息:将计数器置位,重新开始 ...

  9. day8---多线程socket 编程,tcp粘包处理

    复习下socket 编程的步骤: 服务端:   1 声明socket 实例 server = socket.socket()  #括号里不写  默认地址簇使用AF_INET  即 IPv4       ...

  10. socket 粘包问题(转)

    https://www.v2ex.com/t/234785#reply3 1. 面向字节流的 IO 都有这个问题. socket 中 tcp 协议是面向流的协议,发送方发送和接收方的接收并不是一一对应 ...

随机推荐

  1. Ajax跨域请求COOKIE无法带上的解决办法

    原生ajax请求方式: var xhr = new XMLHttpRequest(); xhr.open("POST", "http://xxxx.com/demo/b/ ...

  2. 1. Dubbo原理解析-Dubbo内核实现之SPI简单介绍 (转)

    转载自  斩秋的专栏  http://blog.csdn.net/quhongwei_zhanqiu/article/details/41577159 Dubbo采用 微内核 + 插件体系,使得设计优 ...

  3. 剑指offer(42)和为S的字符串

    题目描述 输入一个递增排序的数组和一个数字S,在数组中查找两个数,是的他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的. 输出描述: 对应每个测试案例,输出两个数,小的先输出. 题目 ...

  4. MySQL基础和JDBC

    第一章 命令行工具 mysqladmin:MySQL服务器管理工具 mysql:MySQL客服端链接工具 mysqldump 演示链接到服务器host=127.0.0.1,用户名为root,密码为空 ...

  5. Spring错误——Spring xml注释——org.xml.sax.SAXParseException; lineNumber: 24; columnNumber: 10; cvc-complex-type.2.3: 元素 'beans' 必须不含字符 [子级], 因为该类型的内容类型为“仅元素”。

    背景:配置spring xml,注释xml中文件元素 错误: Caused by: org.xml.sax.SAXParseException; lineNumber: 24; columnNumbe ...

  6. centos linux查看硬盘型号

    [root@]# smartctl --all /dev/sdasmartctl 6.5 2016-05-07 r4318 [x86_64-linux-3.10.0-957.1.3.el7.x86_6 ...

  7. Oracle 客户端 NLS_LANG 的设置

    参考链接1: https://blog.csdn.net/xinzhan0/article/details/78311417#t3 参考链接2: https://blog.csdn.net/xinzh ...

  8. Pandas 基础(4) - 读/写 Excel 和 CSV 文件

    这一节将分别介绍读/写 Excel 和 CSV 文件的各种方式: - 读入 CSV 文件 首先是准备一个 csv 文件, 这里我用的是 stock_data.csv, 文件我已上传, 大家可以直接下载 ...

  9. 使用 R 语言挖掘 QQ 群聊天记录

    1.获取数据 从 QQ 消息管理器中导出消息记录,保存的文本类型选择 txt 文件.这里获取的是某群从 2016-04-18 到 2016-05-07 期间的聊天记录,记录样本如下所示. 消息记录(此 ...

  10. js 数组元素遍历

    <html> <body> <script type="text/javascript"> var x var mycars = new Arr ...