• 网络编程4 网络编程之FTP上传简单示例&socketserver介绍&验证合法性连接


    今日大纲:

    1.FTP上传简单示例(详细代码)

    2.socketserver简单示例&源码介绍

    3.验证合法性连接//[秘钥加密(urandom,sendall)(注意:中文的!不能用)]

    内容回顾:

    (1)TCP(流)两种黏包现象
    1.连续(两次发送的时间间隔很短暂)发送(send)两个小包,被优化算法nagle,
    给合并到了一起,造成了黏包
    2.一次性接收的数据,并没有将发送的数据完全接受完,第二次接收数据的时候,
    会把第一次剩余的数据给接收过来
    UDP不会发生黏包现象,

    (2)解决方案:
    思想:先接收长度,再接收数据(根据长度拿取数据)
    两种解决方案:
    1.发送真实数据之前,先发送数据的长度,接收方接收到长度之后,先回复一个确认信息,
    发送端再发送真实的数据,接收方按照先发送来的数据长度来接收后面的真实数据.
    2.struct
    A:struct.pack('i',数字)
    B:struct.unpack('i',bytes) 元组类型,需要索引取数据

    (3)缓冲区:解决代码的耦合性(从内存中开辟出的一块空间)
    输出缓冲区
    输入缓冲区
    conn,addr=>长连接

    (4)
    subprocess模块
      注意命令:用gbk进行解码处理,因为windows中文版,默认编码是gbk

    1.FTP上传简单示例(详细代码)

    服务端:

    #重点案例
    import socket
    import json
    import struct
    
    server=socket.socket()
    server.bind(('127.0.0.1',8001))
    server.listen()
    conn,addr=server.accept()
    
    #首先接收文件的描述信息的长度
    struct_data_len=conn.recv(4)
    data_len=struct.unpack('i',struct_data_len)[0]
    
    #通过文件信息的长度将文件的描述信息全部接收
    print('data_len>>>',data_len)
    file_info_bytes=conn.recv(data_len)
    #将字符串转换成bytes类型
    #将文件描述信息转换为字典类型,一遍操作
    file_info_json=file_info_bytes.decode('utf-8')
    file_info_dict=json.loads(file_info_json)#{'file_name': 'aaa.mp4', 'file_size': 24409470}
    
    print(file_info_dict)
    #统计每次接收的累计长度
    recv_sum=0
    
    with open('F:S18ggaaa.mp4','wb') as f:
        while 1:
            every_recv_data=conn.recv(1024)
            print()
    #问题:文件名称不知道这样写不合适,
        #所以,文件需要先发送文件信息

    客户端:

    #需求:客户端给服务端上传文件,一句给的文件信息保存文件
    import os
    import json
    import struct
    import socket
    
    client=socket.socket()
    client.connect(('127.0.0.1',8001))
    
    file_size=os.path.getsize(r'F:Python_workspace_S18week7day292 ftp上传简单示例aaa.mp4')#首先统计数据的长度
    
    
    #传文件的信息,大小,文件名
    file_info={
        'file_name':'aaa.mp4',   #文件的名称
        'file_size':file_size,    #文件的大小
        #路径等等
        #客户端给服务端传递文件,客户端需要循环接收数据大小,
        # 还有文件名,还有服务端的那个路径下,这里没有设置服务端的路径(参考网上设置)
        # 或者可能老师后期可能讲解
    }
    #这里pickle用的少,所以用json比较多,我们这里用json
    #思考:字典发送给服务端,转换成bytes类型的,这里必须用json
    
    #由于字典无法直接转换成bytes类型的数据,所以需要json来将字典转换为
    file_info_json=json.dumps(file_info)
    
    #将字符串转换成bytes类型的数据
    file_info_byte=file_info_json.encode('utf-8')
    
    #为了防止黏包现象,将文件描述信息的长度打包后和文件的描述信息的数据一起发送过去
    data_len=len(file_info_byte)
    data_len_struct=struct.pack('i',data_len)
    
    #发送文件描述信息
    client.send(data_len_struct+file_info_byte)
    
    #定义一个变量,=0,作为每次读取文件的长度的累计值
    sum=0
    #打开的aaa.mp4文件,rb的形式,
    with open('aaa.mp4','rb') as f:
        #循环读取文件内容
        while sum<file_size:             #等于的时候已经读完了
            ##每次读取文件的内容,每次读取1024b字节
            every_read_data=f.read(1024)    #每次读1024个字节,
            #当最后一次的数据不够1024的时候,接收不够的也是不会报错的
            sum+=len(every_read_data)
            client.send(every_read_data)#每次发送1024个字节
        #打开数据文件都是只有一行
        #read可以控制读取的数据的长度
        #readline不可以控制读取的数据的长度
        #思考:数据的长度问题?
            #死循环怎么结束这个循环?
            #锻炼自己的逻辑能力
            #数据读完怎么跳出来?
                #统计每次读的数据的长度
                #首先统计数据的长度os模块

    重点回顾&补充

    import os
    file_size=os.path.getsize(r'F:Python_workspace_S18week7day292 ftp上传简单示例aaa.mp4')
    print(file_size)    #4966541
    
    file_info = {
        'file_name':'aaa.mp4',
        'file_size':file_size,
    }
    
    by_dic1 = bytes(str(file_info)+'中国',encoding='gbk')#b"{'file_name': 'aaa.mp4', 'file_size': 4966541}"
    by_dic = bytes(str(file_info)+'中国',encoding='utf-8')#b"{'file_name': 'aaa.mp4', 'file_size': 4966541}"
    
    print(by_dic1)
    print(by_dic)
    
    k=os.urandom(4)
    print(k,type(k),len(k))
    
    s=bytes('中国',encoding='utf-8')
    s=bytes([1,2,3,4])
    print(s,type(s))
    
    
    '''
    结果:
    4966541 b"{'file_name': 'aaa.mp4', 'file_size': 4966541}xd6xd0xb9xfa" b"{'file_name': 'aaa.mp4', 'file_size': 4966541}xe4xb8xadxe5x9bxbd" b'xd7n+y' <class 'bytes'> 4 b'x01x02x03x04' <class 'bytes'> '''

    2.socketserver简单示例&源码介绍

    简单示例

    服务端:

    #原理:就是一个简单模块的简单使用,不要想的太难
    #这个服务端启用一个,可以启动多个客户端进行同时交流
    #注意:这个是先从客户端向服务端发送消息,再从服务端回客户端消息
    import socketserver
    class Myserver(socketserver.BaseRequestHandler):    #定义类
        def handle(self):
            while 1:
                from_client_msg=self.request.recv(1024)     #self.request=conn
                print(from_client_msg.decode('utf-8'))
                msg=input('服务端说:')
                self.request.send(msg.encode('utf-8'))
    if __name__=='__main__':
        ip_port=('127.0.0.1',8001)
        server=socketserver.ThreadingTCPServer(ip_port,Myserver)
        #调用模块的方法(线程TCP服务)
        #参数:接口&自定义继承类
        #server相当于一个对象,也就是创建了这么个对象
        server.serve_forever()
        #而这里server对象调用serve_forever方法,相当于是开启永远的服务
    
    
    '''
    #推荐思路:(源码问题)
    socketserver源码,要练习看一下.
    python怎么看源码(百度试着看看教程)
    '''

    客户端:

    import socket
    client=socket.socket()
    client.connect(('127.0.0.1',8001))
    
    while 1:
        msg=input('客户端说>>>')
        client.send(msg.encode('utf-8'))
    
        from_server_msg=client.recv(1024)
        print(from_server_msg.decode('utf-8'))

    源码介绍:(这个地方就是提升自己的地方)

    超哥blog:(主要是socketserver的源码解读)

      https://www.cnblogs.com/clschao/articles/9593164.html

    女神blog:

      解读python中socket的源码(http://www.cnblogs.com/Eva-J/p/5081851.html)

    3.验证合法性连接//[秘钥加密(urandom,sendall)(注意:中文的!不能用)]








  • 相关阅读:
    2.6 CMMI2级——供应商协议管理(Supplier Agreement Management)
    使用boch仿真器在x86 PC平台上搭建Linux0.11系统环境(windows下)
    java实现登录验证码
    Hadoop DBOutputFormat的使用
    史蒂芬·金《肖申克的救赎》读后感
    Change Base
    IOS深入学习(20)之Object modeling
    android对话框(Dialog)的使用方法
    郝萌主的微信公众号上线了
    Dell shareplex 与HVR数据复制软件
  • 原文地址:https://www.cnblogs.com/studybrother/p/10235231.html
Copyright © 2020-2023  润新知