• NO.8:自学python之路------并行socket网络编程


    摘要

      一到放假就杂事很多,这次的作业比较复杂,做了一个周,进度又拖了。不过结果还不错。

    正文

    粘包

      在上一节中,如果连续发送过多数据,就可能发生粘包。粘包就是两次发送的数据粘在一起被接收,损坏了数据的完整性。解决方法有两种。

      方案一:

        在发送多个数据之间添加接收确认。这样在完成一次发送以后只有接收到另一端的确认以后才会开始新的发送,避免了粘包的发生。

      方案二:

        首先将发送数据的大小发送给另一端,另一端根据数据的大小接收。一次接收一次发送的数据量,这样也就避免了数据的粘包。例子。

    #方案1
    #server
    f = open(path, 'wb')
    for i in f:
        server.socket.send(i)
    f.close()
    server.socket.recv(1024)
    server.socket.send(b'发送完毕')
    #client
    recv_data = ''
    while True:
        data = client.socket.recv(1024)
        if not data:
            break
        recv_data += data
    client.socket.send(b'recv over')
    other_data = client.socket.recv(1024)
    #方案2
    #server
    size = os.path.getsize(path)
    server.socket.send(size.encode())
    server.socket.recv(1024)
    f = open(path, 'wb')
    for i in f:
        server.socket.send(i)
    f.close()
    server.socket.send(b'发送完毕')
    #client
    size = client.socket.recv(1024)
    client.socket.send(b'start')
    recv_data = ''
    recv_size = 0
    while recv_size < size:
        if size - recv_size < 1024:
            single_size = size - recv_size
        else:
             single_size = 1024
        data = client.socket.recv(single_size)
        recv_size += len(data)
        recv_data += data
    other_data = client.socket.recv(1024)
    View Code

    FTP

      一个简单的FTP过程主要包含以下几个步骤。

      1.读取文件名

      2.检测文件是否存在

      3.打开文件

      4.检测文件大小,文件名

      5.发送文件大小 md5值给客户端

      6.等待客户端确认

      7.开始边读取数据边发送数据

      8.md5确认

      具体例子。

      服务器

    # 服务器端
    import socket
    import os
    import  hashlib
    
    server = socket.socket()
    server.bind(('localhost', 9999))
    server.listen()
    
    while True:
        conn, addr = server.accept()
        print('new conn:', addr)
        while True:
            data = conn.recv(1024)
            data = data.decode()
            if not data:
                print('客户端已断开')
                break
            cmd, filename = data.split()
            print(filename)
            if os.path.isfile(filename):
                f = open(filename, 'rb')
                m = hashlib.md5()
                file_size = os.stat(filename).st_size
                print(file_size)
                conn.send(str(file_size).encode('utf-8'))
                conn.recv(1024)
                for line in f:
                    m.update(line)
                    conn.send(line)
                print('md5:', m.hexdigest())
                f.close()
                conn.send(m.hexdigest().encode('utf-8'))
    View Code

      客户端

    # 客户端
    import socket
    import hashlib
    
    client = socket.socket()
    client.connect(('localhost', 9999))
    
    while True:
        cmd = input('>>').strip()
        if len(cmd) == 0:
            continue
        if cmd.startswith('get'):
            client.send(cmd.encode('utf-8'))
            cmd_res_size = client.recv(1024)  # 接收长度
            print('文件大小 %s' % (cmd_res_size.decode()))
            client.send('准备完毕,开始发送数据'.encode('utf-8'))
            recv_size = 0
            file_name = cmd.split()[1]
            f = open(file_name + '.new', 'wb')
            m = hashlib.md5()
            while recv_size < int(cmd_res_size.decode()):
                if int(cmd_res_size.decode()) - recv_size > 1024:
                    size = 1024
                else:
                    size = int(cmd_res_size.decode()) - recv_size
                data = client.recv(size)
                recv_size += len(data)  # 读取每次接收的数据
                f.write(data)
                m.update(data)
                #print(recv_size)
            else:
                file_md5 = m.hexdigest()
                print('文件接收完毕', recv_size)
                f.close()
            recv_md5 = client.recv(1024)
            print(file_md5, recv_md5.decode())
    client.close()
    View Code

    SocketServer

      SocketServer是Python的一个包,它在socket的基础上封装,可以更加简单的完成并发处理。

      socketserver.TCPServer 继承BaseServer,完成TCP

      socketserver.UDPServer 继承TCPServer,完成UDP

      socketserver.UnixStreamServer 继承TCPServer,完成Unix的TCP

      socketserver.UnixDatagramServer 继承UDPServer,完成Unix的UDP

      使用socketserver的步骤:

      1.创建一个请求处理类,并且这个类要继承BaseRequestHandler,并且需要重写父类中的Handle()方法。

      2.实例化一个Server类,并且传递Server ip和1中创建的请求处理类给它。

      3.server.handle_request()只处理一个请求 server.server_forever()处理多个请求,永久执行。

      4.调用server_close()关闭它。

      BaseServer中的常用方法,例子。

    fileno() # 返回文件描述符
    handle_request # 处理单个请求
    serve_forever(poll_interval=0.5) # 一直运行直到收到shutdown()请求,每poll_interval检查一次,后调用service_actions()结束
    service_actions() # 结束操作
    shutdown() # 停止信号
    server_close() # 清除server
    address_family # 地址簇
    RequestHandlerClass # 请求处理类
    server_address # ip地址
    socket # 同socket
    self.allow_reuse_adress # 允许重用地址 socket中socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
    socket_type # socket使用的协议类型
    self.setup() # 请求来之前 self.handle() # 请求来时 self.finish() # 请求处理之后
    View Code

    作业

      1.用户加密认证

      2.允许多个用户登陆

      3.每个用户有自己的家目录,不能互相访问

      4.对用户进行磁盘配额,可用空间不同

      5.允许用户在ftp_server上随意切换目录

      6.允许用户查看当前目录文件

      7.允许用户上传下载文件,保证文件一致性

      8.传输过程显示进度条

      作业

  • 相关阅读:
    【书签】数据可视化(三)- Seaborn简易入门
    【书签】连续型特征的归一化和离散特征的one-hot编码
    【书签】转:对SVM的个人理解---浅显易懂
    【书签】stacking、blending
    【书签】机器学习相关
    正则表达式:匹配单个数字重复n次
    pandas删除DataFrame中任意字段等于'null'字符串的行
    中文的csv文件的编码改成utf-8的方法
    Eslint 从入门到放弃
    图片压缩的网站工具https://tinypng.com/
  • 原文地址:https://www.cnblogs.com/zk71124720/p/9407286.html
Copyright © 2020-2023  润新知