前言
由于最近在做计算机网络课程设计,了解了一些基本的网络通信协议以及一些网络通信基本原理之后,由于又恰好在学习python,所以不妨产生了用python实现模拟FTP登录过程,类似于相同的ssh协议(远程登陆协议)与FTP实现过程如出一辙。最近也有很长时间没有继续学习了,仅以此篇作为记录。
一、FTP具体实现代码
服务端代码如下
import socket
import struct
import os
import json
from threading import Thread
import hashlib
#获取当前文件所在文件路径
def get_cur_dir():
return os.getcwd()
#获取当前文件夹下所有文件
def get_cur_all(cur_dir):
return os.listdir(cur_dir)
def get_hash(filename):
md5 = hashlib.md5()
with open(filename, 'rb') as f:
for line in f:
md5.update(line)
md5_str=md5.hexdigest()
return md5_str
def sendmsg(filename,conn,base_path):
# 1、制作报头
header_dict = {'filename': filename,
'md5': get_hash(filename),
'total_size': os.path.getsize('%s/%s' % (base_path, filename))
}
head_json = json.dumps(header_dict)
head_bytes = head_json.encode('utf-8')
# 2、发送报文的长度
conn.send(struct.pack('i', len(head_bytes)))
# 发送报头
conn.send(head_bytes)
# 发送数据
with open(filename, 'rb') as f:
for line in f:
conn.send(line)
print('文件发送完毕!\n')
def download_to_file(phone,path):
# 先收报头的长度
obj = phone.recv(4)
head_size = struct.unpack('i', obj)[0]
# 从报头中解析信息
header_bytes = phone.recv(head_size)
head_json = header_bytes.decode('utf-8')
head_dict = json.loads(head_json)
print(head_dict)
filename = head_dict['filename']
total_size = head_dict['total_size']
rec_hash = head_dict['md5']
with open('%s/%s' % (path, filename), 'wb') as f:
recv_size = 0
while recv_size < total_size:
line = phone.recv(1024)
f.write(line)
recv_size += len(line)
print('该文件大小为 ', total_size, '\n已经写入', recv_size)
print('文件上传完毕!\n')
sa_md5 = get_hash(filename)
if rec_hash == sa_md5:
print('文件校验成功,文件无误!')
#发送当前文件夹下的目录列表
def send_sever_list(conn):
rec_msg_list = get_cur_all(get_cur_dir())
rec_msg_str = ' '.join(rec_msg_list)
rec_msg_bytes = rec_msg_str.encode('utf-8')
conn.send(rec_msg_bytes)
#发送当前文件所在路径
def send_sever_path(conn):
cur_dir = get_cur_dir()
cur_dir_bytes = cur_dir.encode('utf-8')
conn.send(cur_dir_bytes)
def action_thread(conn):
base_path = r'D:\computercode\文件传输\sever'
while True:
# 1、接受命令
res = conn.recv(1024)
if not res: break
# 解析命令
cmds = res.decode('utf-8').split()
# print(cmds)
if cmds[0] == 'get':
filename = cmds[1] # 文件名称,用于制作报头以及确定文件大小
sendmsg(filename, conn,base_path)
elif cmds[0] == 'post':
download_to_file(conn,base_path)
elif cmds[0] == 'exit':
print('客户端已经断开连接!')
break
elif cmds[0]=='dirs':
send_sever_list(conn)
elif cmds[0]=='paths':
send_sever_path(conn)
elif cmds[0]=='chdir':
os.chdir(cmds[1])
base_path=os.getcwd()
send_sever_list(conn)
def run():
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.bind(('127.0.0.1',8080))
phone.listen(5)
print('服务器启动成功,正在等待客户连接....')
while True:
conn , client_adrr=phone.accept()
print('一个客户端连接成功,其IP地址为',client_adrr[0])
kh=Thread(target=action_thread,args=(conn,))
kh.start()
conn.close()
phone.close()
if __name__=='__main__':
run()
客户端代码如下
import json
import socket
import struct
import json
import os
import hashlib
download_path=r'D:\computercode\文件传输\user'
def get_cur_dir():
return os.getcwd()
def get_cur_all(cur_dir):
return os.listdir(cur_dir)
def show_info_curpath_sever(phone):
print('正在等待服务端发送信息....')
sv_cur_path_bytes = phone.recv(1024)
sv_cur_path_str = sv_cur_path_bytes.decode('utf-8')
print(sv_cur_path_str)
def show_info_curdir_sever(phone):
print('正在等待服务器发送信息.....')
sv_cur_all_bytes = phone.recv(1024)
sv_cur_all_str = sv_cur_all_bytes.decode('utf-8')
sv_cur_all_list = sv_cur_all_str.split()
for item in sv_cur_all_list:
print(item)
def get_hash(filename):
md5 = hashlib.md5()
with open(filename, 'rb') as f:
for line in f:
md5.update(line)
md5_str=md5.hexdigest()
return md5_str
def download_to_file(phone):
# 先收报头的长度
obj = phone.recv(4)
head_size = struct.unpack('i', obj)[0]
# 从报头中解析信息
header_bytes = phone.recv(head_size)
head_json = header_bytes.decode('utf-8')
head_dict = json.loads(head_json