• 利用IO多路复用实现的ftp的上传与下载


    程序的基本框架图

    这个代码我写的时候偷了点懒,没有写关于data的内容  我将需要下载的文件和需要上传的文件都各自放在其client或者server下

    其实这个代码很简单,只要理解了IO多路复用,get与put其实两个可逆的过程,注意 发送 与 接受 的位置顺序就可以了

    我是新手 希望大家指教

    代码 客户端 :

    import socket
    import os
    import hashlib
    import time
    #client的登陆页面我后续在写
    class myclient(object):
        def __init__(self):
            pass
        def login(self):
            self.client=socket.socket()
            #我测试的时候应该往linux上服务器端传输文件
            # 手动输入账户与端口号码
            self.client.connect(("localhost",23))
        def interactive(self):#设计一个用来交互的函数可用来输入命令
            while True:
                command=input("请输入命令").strip()#命令模式参考read me
                if not command:
                    continue
                else:
                    cmd=command.split()[0]
                    if hasattr(self,cmd):
                        func=getattr(self,cmd)
                        func(command)
                #通过这个函数 将下面的dowload与put链接在了一起
        #下载文件
        def get(self,command):
            #把文件名字发过去看是否可以执行(其实就是发过去看服务器端到底有没有这个文件可以下载)
            self.client.sendall(command.encode())
            #根据返回的状态码我们来判断是否该继续进行
            filename=command.split()[1]
            status_code=self.client.recv(1024).decode()
            if status_code=="203":
                print("我们可以进行下载".center(50,"-"))
            #接下来我们要继续判断是否已经下载了一部分,1.继续下载 2.从零开始下载
                if os.path.isfile(filename):#判断文件是否已经存在过
                    self.client.sendall("000".encode())#发送一个 000命令告诉服务器 这个文件在客户端已经下载过
                    recive_size=os.stat(filename).st_size#已经接受的尺寸
                    self.client.sendall(str(recive_size).encode())#将尺寸发送给服务器端
                    status_code=self.client.recv(1024).decode()
                    if status_code=="426":#文件曾经下载过
                        print("我们需要接着继续传输")
                    elif status_code=="312":
                        print("文件已经下载完毕不需要在下载了")
                else:
                    self.client.sendall("402".encode())
                    print("开始传输")
                    recive_size=0
                filesize=self.client.recv(1024).decode()
                print(filesize)#所需要下载的文件的尺寸
                filesize=int(filesize)
                m=hashlib.md5()
                with open(filename,"ab") as f:
                    filesize+=recive_size
                    print("源文件的总大小为",filesize)
                    print("已接受文件大小为",recive_size)
                    while recive_size < filesize:
                        a=filesize-recive_size
                        print(a)
                        if a>1024:
                            size=1024
                        else:
                            size=a
                        data=self.client.recv(size)
                        recive_size+=len(data)
                        f.write(data)
                        m.update(data)
    
                    new_hexdigest=m.hexdigest()
                    server_hexdigest=self.client.recv(1024).decode()
                    if new_hexdigest==server_hexdigest:
                        print("文件一致")
    
    
            else:
                print("文件在服务器端不存在!")
    
    #上传文件将client端的文件传送给server端
        def put(self,command):
            self.client.sendall(command.encode())
            filename=command.split()[1]#客户端发来的判断这里是否有这个文件
            if os.path.isfile(filename):
                self.client.sendall("203".encode())#有这个文件可以上传
                file_allsize=os.stat(filename).st_size #获得本地文件的大小
                while True:
                    try:
                        status_code=self.client.recv(1024).decode()#获取状态码后继续执行
                        break
                    except:
                        continue
                if status_code=="402":
                    print("服务器端未下载过,从头开始发送")
                    file_hasrecivesize=0
                    self.client.sendall(str(file_allsize).encode())
                elif status_code=="000":#此状态码说明客户端已经下载过
                    file_hasrecivesize=self.client.recv(1024).decode()
                    file_hasrecivesize=int(file_hasrecivesize)
                    if file_hasrecivesize<file_allsize:#如果已接受文件尺寸小于总尺寸那么传一个继续下载信号
                        self.client.sendall("426".encode())
                    elif file_hasrecivesize==file_allsize:
                        self.client.sendall("312".encode())
                        print("文件已经下载过无需继续进行下载")
    
                    shouldsendsize=file_allsize-file_hasrecivesize
                    self.client.sendall(str(shouldsendsize).encode())
    
                m=hashlib.md5()
                with open(filename,"rb") as file:
                    file.seek(file_hasrecivesize)
                    for line in file:
                        m.update(line)
                        self.client.sendall(line)
                self.client.sendall(m.hexdigest().encode())
                print(self.client.recv(1024).decode())
    
    
    
            else:
                print("服务器端无此文件可供下载")
                self.client.sendall("110".encode())
    #之后我们写的是命令行的操作指示传递
    
    
    
    d=myclient()
    d.login()
    d.interactive()

    代码 服务器端:

    import hashlib
    import socket
    import os
    import selectors
    global command
    global conn
    import time
    sel=selectors.DefaultSelector()
    #创建一个 sel实例
    
    def accept(sock,mask):
        sock=sock
        mask=mask
        conn,addr=sock.accept()
        conn.setblocking(False)
        sel.register(conn,selectors.EVENT_READ,read)
    def read(conn, mask):
        data = conn.recv(1000)  # 获得命令
        if data:
            print(data)
            command_str = data.decode()
            print(command_str)
            if command_str.split()[0] == 'get':
                get(conn, command_str)
            elif command_str.split()[0]=="put":
                put(conn,command_str)
    
            else:
                conn.send(b'404') # Hope it won't block
        else:
            print('closing', conn)
            sel.unregister(conn)
            conn.close()
    #与客户端的下载进行交互
    def get(conn,command):
        filename=command.split()[1]#客户端发来的判断这里是否有这个文件
        if os.path.isfile(filename):
            conn.sendall("203".encode())#有这个文件可以下载
            file_allsize=os.stat(filename).st_size #获得本地文件的大小
            while True:
                try:
                    status_code=conn.recv(1024).decode()#获取状态码后继续执行
                    break
                except:
                    continue
            if status_code=="402":
                print("客户端未下载过,从头开始发送")
                file_hasrecivesize=0
                conn.sendall(str(file_allsize).encode())
            elif status_code=="000":#此状态码说明客户端已经下载过
                while True:
                    try:
                        file_hasrecivesize=conn.recv(1024).decode()#获取状态码后继续执行
                        break
                    except:
                        continue
                file_hasrecivesize=int(file_hasrecivesize)
                print(file_hasrecivesize)
                if file_hasrecivesize < file_allsize:#如果已接受文件尺寸小于总尺寸那么传一个继续下载信号
                    conn.sendall("426".encode())
                    print("文件小于总尺寸")
                elif file_hasrecivesize == file_allsize:
                    conn.sendall("312".encode())
                    print("文件等于总尺寸")
                shouldsendsize=file_allsize-file_hasrecivesize
                conn.sendall(str(shouldsendsize).encode())
    
            m=hashlib.md5()
            with open(filename,"rb") as file:
                file.seek(file_hasrecivesize)
                for line in file:
                    m.update(line)
                    conn.sendall(line)
            conn.sendall(m.hexdigest().encode())
            return
    
        else:
            print("服务器端无此文件可供下载")
            conn.sendall("110".encode())
    
    def put(conn,command):
        filename=command.split()[1]
        while True:
            try:
                status_code=conn.recv(1024).decode()#获取状态码后继续执行
                break
            except:
                continue
        if status_code=="203":
            print("我们可以进行下载".center(50,"-"))
        #接下来我们要继续判断是否已经下载了一部分,1.继续下载 2.从零开始下载
            if os.path.isfile(filename):#判断文件是否已经存在过
                conn.sendall("000".encode())#发送一个 000命令告诉服务器 这个文件在客户端已经下载过
                recive_size=os.stat(filename).st_size#已经接受的尺寸
                conn.sendall(str(recive_size).encode())#将尺寸发送给服务器端
                while True:
                    try:
                        status_code=conn.recv(1024).decode()#获取状态码后继续执行
                        break
                    except:
                        continue
                if status_code=="426":#文件曾经下载过
                    print("我们需要接着继续传输")
                elif status_code=="312":
                    print("文件已经下载完毕不需要在下载了")
            else:
                conn.sendall("402".encode())
                print("开始传输")
                recive_size=0
            while True:
                try:
                    filesize=conn.recv(1024).decode()#所需要下载的文件的尺寸
                    break
                except:
                    continue
    
            filesize=int(filesize)
            print(filesize)
            m=hashlib.md5()
            with open(filename,"ab") as f:
                filesize+=recive_size
                print("源文件的总大小为",filesize)
                print("已接受文件大小为",recive_size)
                while recive_size < filesize:
                    a=filesize-recive_size
                    print(a)
                    if a>1024:
                        size=1024
                    else:
                        size=a
                    data=conn.recv(size)
                    recive_size+=len(data)
                    f.write(data)
                    m.update(data)
                new_hexdigest=m.hexdigest()
                while True:
                    try:
                        server_hexdigest=conn.recv(1024).decode()
                        break
                    except:
                        continue
    
                if new_hexdigest==server_hexdigest:
                    print("文件一致")
                    conn.send("文件一致".encode())
        else:
            print("文件在服务器端不存在!")
    
    
    
    server=socket.socket()#创建一个实例
    #监听的链接 我选择从客户端接收
    server.bind(("localhost",23))
    server.listen(1000)
    
    server=socket.socket()
    server.bind(("localhost",23))
    server.listen(1000)
    server.setblocking(False)#设置为非阻塞模式
    sel.register(server,selectors.EVENT_READ,accept)
    while True:
        events=sel.select()
        for key,mask in events:
            callback=key.data#相当于callback=accept
            callback(key.fileobj,mask)#调用accept keyfileobj相当于一个实例作为形参传进去

    其实这个程序要理解 多路复用的原理,在服务器端 服务器一般是不会等待接受的 如果100个链接过来都没有那么就会立即返回一个信号结束,所以我们要用一个while循环来等recv信息继续进行

    才能正确的运行代码!!!!

  • 相关阅读:
    错误:net::ERR_BLOCKED_BY_CLIENT
    ui-grid angularjs
    angular Js 回车处理
    百度云盘-真实地址 F12 控制台
    Js 跨域CORS报错 Response for preflight has invalid HTTP status code 405
    angularjs 路由参数
    AngularJs Angular数据类型判断
    Bootstrap+AngularJS对话框实例
    AngularJs表单自动验证
    IIS7.5上的REST服务的Put操作发生HTTP Error 405.0
  • 原文地址:https://www.cnblogs.com/shidi/p/7475476.html
Copyright © 2020-2023  润新知