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