zoukankan      html  css  js  c++  java
  • python学习Day31--粘包

    【基本知识点】

    一、回顾

    1、TCP编码、UDP编码、PyCharm带颜色输出

    2、三次握手:客服端先发起

      客服端先发起连接请求;

      服务器回复确认收到,连接客服端的请求;

      客服端回复收到请求,可以连接。

    3、四次挥手:谁可以先发起请求

      客服端发起一个请求,代表我没有数据继续发送了,但是如果你有数据继续发,我可以继续接受;

      服务器发送一个确认收到的ACK

      服务器再发送一个断开连接的请求,标识可以断开连接了;

      客服端回复一个确认能收到。

    【三个标识】:

    ACK:确认收到;            SYN:请求连接的这么一个标识;       FIN:请求断开的这么一个标识

    4、UDP特点:不面向连接,不可靠,面向数据,速度快。

    5、TCP特点:可靠的,基于连接的,面向字节流形式的。

    6、OSI五层模型:应用层(http, https, ftp),传输层(tcp, udp),网络层(ip),数据链路层(arp),物理层。

    7、socket:是一个模块,是一个套接字,是一个类,是传输层和应用层之间的一个抽象层。

    8、子网掩码:子网掩码&IP地址  得到网段

    二、执行命令

    在py代码中如何去调用操作系统的命令。

    1、新模块:subprocess

    1 r = subprocess.Popen('dir',shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
    2 # 各个参数说明subprocess.Popen(cmd,shell=True,subprocess.stdout,subprocess.stderr)
    3 # cmd:代表系统命令
    4 # shell = True:代表这条命令是 系统命令,告诉操作系统,将cmd当成系统命令去执行
    5 # stdout:是执行完系统命令之后,用于保存结果的一个管道
    6 # stderr:是执行完系统命令之后,用于保存错误的一个管道

    2、一个案例需求:

      客服端发送要执行的命令

      服务器执行,执行完成将结果返回给客服端

      客服端拿到结果呈现到用户眼前

     1 # *******************服务端**********************开始
     2 import socket
     3 import subprocess
     4 
     5 sk = socket.socket()
     6 sk.bind(('127.0.0.1',8080))
     7 sk.listen()
     8 
     9 conn,addr = sk.accept()
    10 while 1:
    11     cmd = conn.recv(1024).decode('utf-8')
    12     r = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
    13     stdout = r.stdout.read()
    14     stderr = r.stderr.read()
    15     if stderr:
    16         conn.send(stderr)
    17     else:
    18         conn.send(stdout)
    19 
    20 conn.close()
    21 sk.close()
    22 # *******************服务端**********************结束
    23 
    24 
    25 # *******************客服端**********************开始
    26 import socket
    27 
    28 sk = socket.socket()
    29 
    30 sk.connect_ex(('127.0.0.1',8080))
    31 while 1:
    32     cmd = input('请输入一个命令>>>')
    33     sk.send(cmd.encode('utf-8'))
    34 
    35     result = sk.recv(102400).decode('gbk')
    36 
    37     print(result)
    38 
    39 
    40 sk.close()
    41 # *******************客服端**********************结束
    案例

    三、粘包

    1、粘包问题:(只有tcp协议才会发生粘包)

      ① 发送端发送数据,接收端不知道应该如何去接收,造成一种数据混乱的现象。

      ② udp不会发生粘包,udp协议本层对一次收发数据大小的限制是:

        65535 - ip包头(20) - udp包头(8) = 65507

      ③ 站在数据链路层,因为网卡的MTU一般被限制在了1500,所以对于数据链路层来说,一次收发数据的大小被限制在 1500 - ip包头(20) - udp包头(8) = 1472

      【结论】:

        如果sendto(num) 的num > 65507  则会报错;

        1472 < num < 65507 会在数据链路层拆包,而udp本身就是不可靠协议,所以一旦拆包之后,造成的多个小数据包在网络传输中,如果丢任何一个,那么此次数据传输失败。

    2、粘包的缘由:两种

      ① 合包机制:(Nagle算法)将多次连续发送且时间间隔较小的数据,进行打包成一块数据传送。

      ② 拆包机制:在发送端因为网卡MTU限制,会将大的超过MTU限制的数据进行拆分,拆分为多个小的数据进行传输;当传输目标主机的操作系统层时,会重新将多个小的数据合并成原本的数据。

    3、粘包测试

     1 # *******************服务端**********************开始
     2 import socket
     3 sk = socket.socket()
     4 
     5 sk.bind(('127.0.0.1',8888))
     6 sk.listen()
     7 
     8 conn,addr = sk.accept()
     9 
    10 conn.send(b'hello')
    11 conn.send(b'world')
    12 
    13 conn.close()
    14 sk.close()
    15 
    16 # *******************服务端**********************结束
    17 
    18 
    19 # *******************客服端**********************开始
    20 import socket
    21 sk = socket.socket()
    22 
    23 sk.connect_ex(('127.0.0.1',8888))
    24 
    25 msg1 = sk.recv(1024)
    26 print('msg1:',msg1)  # 粘包发生时,打印:msg1: b'helloworld'
    27 
    28 msg2 = sk.recv(1024)
    29 
    30 print('msg2:',msg2)
    31 
    32 sk.close()
    33 # *******************客服端**********************结束
    粘包测试

    结果:

    【课后练习】

    1、文件的上传下载

     1 # *******************服务端**********************开始
     2 # 功能不完善,只能实现当前目录。后期可以加上,目录的切换功能
     3 import socket
     4 import json
     5 
     6 sk = socket.socket()
     7 sk.bind(('127.0.0.1',8888))
     8 sk.listen()
     9 
    10 conn,addr = sk.accept()
    11 while 1:
    12     # 通信
    13     str_dic = conn.recv(4800).decode('utf-8')
    14     dic = json.loads(str_dic) # 得到字典
    15     if dic['opt'] == 'upload':
    16         # 上传
    17         filename = 'shangchuan_' + dic['filename']
    18         with open(filename, 'w', encoding='utf-8') as f:
    19             f.write(dic['content'])
    20         break
    21 
    22     elif dic['opt'] == 'download':
    23         # 下载
    24         filename = dic['filename']
    25         with open(filename,'r',encoding='utf-8') as f:
    26             content = f.read()
    27         dic['content'] = content
    28         str_dic = json.dumps(dic)
    29         conn.send(str_dic.encode('utf-8'))
    30         break
    31 
    32 conn.close()
    33 sk.close()
    34 # *******************服务端**********************结束
    35 
    36 
    37 # *******************客服端**********************开始
    38 import os
    39 import socket
    40 import json
    41 
    42 sk = socket.socket()
    43 sk.connect_ex(('127.0.0.1',8888)) # 带返回值,如果出粗,不会报错会返回错误的编码
    44 
    45 menu = {'1':'upload','2':'download'}
    46 for k,v in menu.items():
    47     print(k,v)
    48 
    49 num = input("请输入功能选项:")
    50 if num == '1':
    51     # 上传功能
    52     dic = {'opt':menu.get(num),'filename':None,'content':None}
    53     file_path = input("请输入一个文件的绝对路径:")
    54     # D:/wendang/PyCharmCode/Python学习/day31 粘包/文件上传下载/xxx.py
    55     filename = os.path.basename(file_path)
    56     with open(file_path,'r',encoding='utf-8') as f:
    57         content = f.read()
    58 
    59     dic['filename'] = filename
    60     dic['content'] = content
    61 
    62     # 字典序列化
    63     str_dic = json.dumps(dic)
    64     sk.send(str_dic.encode('utf-8'))
    65 
    66 elif num == '2':
    67     # 下载功能
    68     filename = input("请输入文件名:")
    69     dic = {'opt':menu.get(num),'filename':filename,'content':None}
    70     str_dic = json.dumps(dic)
    71     sk.send(str_dic.encode('utf-8'))
    72 
    73     str_dic = sk.recv(4800).decode('utf-8')
    74     dic = json.loads(str_dic)
    75     filename = 'xiazai_' + dic['filename']
    76     with open(filename,'w',encoding='utf-8') as f:
    77         f.write(dic['content'])
    78 
    79 else:
    80     print("输入错误")
    81 
    82 sk.close()
    83 # *******************客服端**********************结束
    文件的上传下载

    时间:2020-03-17  17:15:10

    作者(QQ):931935931

  • 相关阅读:
    CF1082E Increasing Frequency
    CF1083B The Fair Nut and String
    week2
    CF1082G Petya and Graph
    后缀数组学习笔记
    单纯形法
    验证rbd的缓存是否开启
    如何删除一台OSD主机
    Mon失效处理方法
    查询osd上的pg数
  • 原文地址:https://www.cnblogs.com/fengxb1213/p/12486856.html
Copyright © 2011-2022 走看看