表示编程这条路真得好难走,后悔大学没有读信息专业啊。
第七周的作业:
1. 用户登陆
2. 上传/下载文件
3. 不同用户家目录不同
4. 查看当前目录下文件
刚开始没有一点思路,上网查了很多资料,还自学了FTP。吐槽一句,讲师真是太不负责了,作业要求不详细,还没有思路。
要实现通信,需要7个层次:物理层,数据链路(mac地址),网络层(IP),传输层(有标准的数据类型, TCP/IP 三次握手四次断开, UDP),会话层(http,smtp),表示层,应用层。 传输过程中就需要做到的事情是接收和发送,在python中,这部分功能被封装在socket模块的socket类中。
要实现文件上传和下载,肯定是需要两个端口:一个是服务器端(server),另外一个是客户端(client)。大致的交互流程如下:

理清楚思路之后,就是开始写代码了。
server端的代码如下:
import socket
import os
import sys
sys.path.append('..')
from conf import setting
com_path = setting.DATABASE
def run():
server = socket.socket()
server.bind(('localhost',6969))
server.listen()
while True:
print('等待客户端的连入')
conn, addr = server.accept()
print('收到来自%s,%s的请求'%(str(conn),str(addr)))
data = conn.recv(1024).decode()
server_path = '%s\\%s\\%s'%(com_path['path'],com_path['server'],data)
print('当前目录下的文件有:')
print(os.listdir(server_path))
#检查服务器端是否已经有目录存在,要是没有的化,创建一个目录
if os.path.isdir(server_path):
print('该用户的目录已经存在')
else:
os.mkdir(server_path)
print('成功在远程端创建%s的目录'%data)
while True:
try:
data = conn.recv(1024)
if len(data) == 0:
continue
else:
cmd, filename = data.decode().split()
file_path = "%s\\%s.txt"%(server_path,filename)
print(cmd,filename)
if cmd == 'download':
print(file_path)
if os.path.isfile(file_path):
with open(file_path,'rb') as f:
file_size = os.stat(file_path).st_size
conn.send(bytes(str(file_size),encoding='utf-8'))
print('已经成功传送了文件大小%s'%str(file_size))
conn.recv(1024) #服务器端发送文件大小后,接受客户端的相应
for line in f:
conn.send(bytes(str(line),encoding='utf-8'))
elif cmd == 'upload':
receive_file_size = conn.recv(1024).decode()
conn.send('准备好接收文件'.encode())
receive_size = 0
file_total_size = int(receive_file_size)
with open(file_path, 'wb') as f:
while receive_size < file_total_size:
data = conn.recv(1024)
receive_size += len(data)
f.write(data)
print('file recv done')
print(receive_size,file_total_size)
print('更新后目录下的文件有:')
print(os.listdir(server_path))
except Exception:
print('客户端链接断开')
break
server.close()
client端的代码如下:
import socket
import sys
sys.path.append('..')
import os
from conf import setting
com_path = setting.DATABASE
current_user = None
def auth(func):
def wrapper(*args,**kwargs):
global current_user
username, pwd = input('请输入您的用户名,密码:').strip().split(',')
user_info_path = '%s\\%s.txt'%(com_path['path'],com_path['user_info'])
exist_flag = False
not_user = False
with open(user_info_path,'r') as f:
while not exist_flag:
for line in f:
if line.startswith(username):
if line.strip().split('|')[1] == pwd:
print('登录成功')
current_user = username
func()
break
exist_flag = True
not_user = True
else:
print('密码错误')
if not not_user:
print('用户不存在')
return wrapper
@auth
def run():
client = socket.socket()
client.connect(('localhost',6969))
client_path = '%s\\%s\\%s'%(com_path['path'],com_path['client'],current_user)
client.send(current_user.encode())#将用户名发送给服务器端,看看是否有这个客户的目录
while True:
inp = input(">>:").strip()
if len(inp) == 0:
continue
try:
cmd,filename = inp.split()
file_path = "%s\\%s.txt"%(client_path,filename)
except:
print('输入有误,请重新输入')
continue
try:
if cmd == 'download':
client.send(inp.encode())
receive_file_size = client.recv(1024).decode()
print('server file size',receive_file_size)
client.send('准备好接收文件'.encode())
if os.path.isdir(client_path):
print('该用户的目录已经存在')
else:
os.mkdir(client_path)
print('成功在远程端创建%s的目录'%data)
receive_size = 0
file_total_size = int(receive_file_size)
with open(file_path,'wb')as f:
data = client.recv(1024)
receive_size += len(data)
f.write(data)
print('file recv done')
print(receive_size,file_total_size)
elif cmd == 'upload':
# try:
if os.path.isfile(file_path):
client.send(bytes(inp,encoding='utf-8'))
with open(file_path,'rb') as f:
file_size = os.stat(file_path).st_size
print(file_size)
client.send(bytes(str(file_size),encoding='utf-8'))
print('已经成功传送了文件大小%s'%str(file_size))
client.recv(1024)
for line in f:
client.send(bytes(str(line), encoding='utf-8'))
# except Exception:
# print('只能上传文件')
except Exception:
break
client.close()
run()
本来想在写一个自己的类,然后继承socket类的,但是无奈,老是出现‘OSError: [WinError 10022] 提供了一个无效的参数’错误,这个BUG我也修改不了。所以就放弃了运用面向对象的方法。希望学到以后能回过头来找出今天没有能力解决的原因吧。
浙公网安备 33010602011771号