程序的基本框架图
这个代码我写的时候偷了点懒,没有写关于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信息继续进行
才能正确的运行代码!!!!