python实现模拟FTP文件传输

前言

一、FTP具体实现代码

二、相关函数及其说明

1.建立连接函数

2.线程处理函数

3.文件下载函数

4.文件上传函数

5.哈希函数

6.文件目录函数

三.原理概述

3.1 FTP原理概述

3.2  FTP工作流程

3.3 TCP三次握手四次挥手

3.4 socket通信过程

四.重要问题及其解决方式

4.1流式协议

4.2粘包问题

4.3简单处理方法

4.4复杂处理方法


前言

  由于最近在做计算机网络课程设计,了解了一些基本的网络通信协议以及一些网络通信基本原理之后,由于又恰好在学习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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值