Python使用socket传输文件
发布日期:2021-11-16 18:49:33 浏览次数:6 分类:技术文章

本文共 3823 字,大约阅读时间需要 12 分钟。

昨晚的高网实验要求用Socket编程实现两台机器的文件传输,还要记录传输时间并进行MD5验证,于是便用python简单实现了下。

过程其实挺简单,先建立两个进程的TCP连接,然后client先向server发送文件信息(包括文件名和文件大小以及MD5值),这个文件信息的大小是预先设定好的,也就是client和server都知道,这样server才能准确判断接收的数据哪些是文件信息哪些是真正的文件。这里用到了库对文件信息进行处理。这里的struct类似于c中的结构体,可以把变量转换成具有c结构体形式的字符串。比如我的例子中定义了这样一个struct形式:

HEAD_STRUCT = '128sIq32s'

它就相当于c中如下结构体:

struct{    char fileName[128]; //文件名    int fileNameSize;  //文件名长度    long long fileSize;  //文件大小    char MD5[32];  //MD5值}

这个结构体的空间大小是固定的,于是当client按照这个格式发送文件信息的时候,server也以相同的格式接收信息。由于文件名的长度不固定,于是这里我还发送了一个文件名的长度,这样server就可以根据这个长度对fileName进行截取。

然后再发送文件,这里我是用1024B的缓冲区进行接收(最后一次小于或等于1024B)。

# receiveimport socketimport hashlibimport structHOST = 'localhost'PORT = 1307BUFFER_SIZE = 1024HEAD_STRUCT = '128sIq32s'info_size = struct.calcsize(HEAD_STRUCT)def cal_md5(file_path):    with open(file_path, 'rb') as fr:        md5 = hashlib.md5()        md5.update(fr.read())        md5 = md5.hexdigest()        return md5def unpack_file_info(file_info):    file_name, file_name_len, file_size, md5 = struct.unpack(HEAD_STRUCT, file_info)    file_name = file_name[:file_name_len]    return file_name, file_size, md5def recv_file():    try:        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)        server_address = (HOST, PORT)        sock.bind(server_address)        sock.listen(1)        client_socket, client_address = sock.accept()        print "Connected %s successfully" % str(client_address)        file_info_package = client_socket.recv(info_size)        file_name, file_size, md5_recv = unpack_file_info(file_info_package)        recved_size = 0        with open(file_name, 'wb') as fw:            while recved_size < file_size:                remained_size = file_size - recved_size                recv_size = BUFFER_SIZE if remained_size > BUFFER_SIZE else remained_size                recv_file = client_socket.recv(recv_size)                recved_size += recv_size                fw.write(recv_file)        md5 = cal_md5(file_name)        if md5 != md5_recv:            print 'MD5 compared fail!'        else:            print 'Received successfully'    except socket.errno, e:        print "Socket error: %s" % str(e)    finally:        sock.close()if __name__ == '__main__':    recv_file()
# sendimport socketimport osimport hashlibimport structHOST = 'localhost'PORT = 1307BUFFER_SIZE = 1024HEAD_STRUCT = '128sIq32s'def cal_md5(file_path):    with open(file_path, 'rb') as fr:        md5 = hashlib.md5()        md5.update(fr.read())        md5 = md5.hexdigest()        return md5def get_file_info(file_path):    file_name = os.path.basename(file_path)    file_name_len = len(file_name)    file_size = os.path.getsize(file_path)    md5 = cal_md5(file_path)    return file_name, file_name_len, file_size, md5def send_file(file_path):    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)    server_address = (HOST, PORT)    file_name, file_name_len, file_size, md5 = get_file_info(file_path)    file_head = struct.pack(HEAD_STRUCT, file_name, file_name_len, file_size, md5)    try:        print "Start connect"        sock.connect(server_address)        sock.send(file_head)        sent_size = 0        with open(file_path) as fr:            while sent_size < file_size:                remained_size = file_size - sent_size                send_size = BUFFER_SIZE if remained_size > BUFFER_SIZE else remained_size                send_file = fr.read(send_size)                sent_size += send_size                sock.send(send_file)    except socket.errno, e:        print "Socket error: %s" % str(e)    finally:        sock.close()        print "Closing connect"if __name__ == '__main__':    file_path = raw_input('Please input file path:')    if not file_path:        file_path = 'test.txt'    send_file(file_path)
注意: - 在某些时候(比如传输大文件)会发生丢包的情况,这时候接收的文件大小会小于发送文件的大小,两个MD5值也会不一样。

转载地址:https://blog.csdn.net/Thare_Lam/article/details/49506565 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:动态规划之备忘录法
下一篇:Android中Listview的getChildAt()只能更新当前显示在屏幕上的Item的解决办法

发表评论

最新留言

能坚持,总会有不一样的收获!
[***.219.124.196]2024年03月29日 19时54分00秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

种树:二叉树、二叉搜索树、AVL树、红黑树、哈夫曼树、B树、树与森林 2021-06-30
【C++】攻克哈希表(unordered_map) 2021-06-30
转:【答学员问】- 该如何根据岗位学习相关技能 2021-06-30
转:【答学员问】有什么经验教训,是你在面试很多次之后才知道的? 2021-06-30
消息队列:解耦、异步、削峰,现有MQ对比以及新手入门该如何选择MQ? 2021-06-30
【奇技淫巧】-- 三角形最小路径和 2021-06-30
【小技巧】argc和argv的用法 2021-06-30
学不下去了怎么办? 2021-06-30
二叉树的前中后序遍历(迭代法)(带动画) 2021-06-30
【小技巧】【XShell】【Xftp】Windows桌面与Linux虚拟机互传文件 2021-06-30
【redis入门】Centos下安装redis 2021-06-30
【redis入门】redis安装后相关知识串讲 2021-06-30
【redis】来吧,展示一下redis 发布-订阅模式 2021-06-30
讲通C/C++预编译/条件编译指令 #ifdef,#ifndef,#endif,#define,… 2021-06-30
【redis6.0.6】redis源码慢慢学,慢慢看 -- 第二天:空间配置(zmalloc) 2021-06-30
当下热点词再学:redis缓存预热、更新、降级,限流 2021-06-30
【redis6.0.6】redis源码慢慢学,慢慢看 -- 第五天:adlist 2021-06-30
别抖,OK? 操作系统抖动现象、网络抖动与延迟、函数抖动之防抖与节流,串讲 2021-06-30
第六天:网络处理(anet部分)-- redis源码慢慢学,慢慢看【redis6.0.6】 2021-06-30
通过域名获取主机IP -- struct addrinfo 2021-06-30