layout: post
title: “python实现简单的文件传输程序-TCP”
date: 2019-05-18
description: “一次计网作业,分UDP和TCP”
tag: python
说明
- 本程序仅在python3.7.3下测试无错
TCP
因为代码比较短所以直接贴了,程序实现了如下功能:
- 服务端与单个客户端建立一条TCP连接,客户端从服务端的目录下下载指定文件到所在目录下
- 传输文件的大小,修改日期等管理元数据
- 显示传输的进度条
- 多线程同时与多个客户端建立连接
- 更友好的用户界面
- 客户端的上传功能
运行过程
- 在电脑A上打开服务端程序,将ip和端口(若不提示端口被占用则无需修改)改为你自己的,运行,同时将想要被下载的文件放在程序同一目录下;
- 在电脑B上打开客户端程序,将ip和端口改为服务端的ip和端口,运行,输入想要下载文件名+回车,等待下载完成,可在程序同一目录下看到下载的文件。
实现过程
首先建立TCP连接,然后客户端向服务端 send 文件名,发出下载请求,服务端查找本地目录,若找到该文件,则发送,发送具体过程为先发送文件头大小,再发送文件头(即文件名,大小等管理元数据),最后发送文件内容。若找不到文件,则发送文件头大小为0,客户端通过收到的文件头大小来判断是否能下载该文件。
文件头用字典定义如下:
#文件头
header = {
'file_name': file_name,
'file_size': os.path.getsize(file_path),
'file_ctime': os.path.getctime(file_path),
'file_atime': os.path.getatime(file_path),
'file_mtime': os.path.getmtime(file_path)
}
文件头的传输过程:序列化dumps->打包pack->发送send->接受recv->解包unpack->反序列化loads
为什么要进行这一系列操作?因为在网络上传输的是二进制的数据,而我们的文件头定义为一个字典。
关于序列化
- 序列化:把不可传输的对象转换为可存储在磁盘中的或可在网络中传输的数据的过程
- 反序列化:把在磁盘中储存的,或者网络中传送的持久化数据转换为对象
程序使用的相关模块是pickle或者cPickle,pickle.dumps()
方法可以把任意对象序列化返回一个字符串,而pickle.loads()
则可以反序列化重新得到header字典。但是用pickle序列化的数据只能被python识别,并且可能不同版本的python互相都不兼容,如果要在不同的编程语言之间传递对象,就必须序列化为标准格式,如XML或JSON,需要用json等模块,具体内容在此不详细叙述。
关于打包
其实就是把要发送的数据按已定义的格式拼接起来形成数据包来发送。
相关模块是struct,定义数据包格式如下:
header_struct = struct.Struct('i1024s')
data_struct = struct.Struct('1024s')
相当于C语言中的:
struct header_struct {
int i;
//1024个B
}
所用的struct格式符:
格式符 | Python Type | 字节数 |
---|---|---|
i,I(大写i),l(小写L) | intenger | 4 |
s | bytes | 1 |
而从文件中读取的数据本身就是二进制,所以可以直接发送。
客户端
import socket
import struct
import pickle
import time
import os
server_ip = '127.0.0.1'
server_port = 5200
file_dir = os.path.dirname(os.path.abspath(__file__))
header_struct = struct