Python使用socket传输文件
2015-10-30 09:33
741 查看
昨晚的高网实验要求用Socket编程实现两台机器的文件传输,还要记录传输时间并进行MD5验证,于是便用python简单实现了下。
过程其实挺简单,先建立两个进程的TCP连接,然后client先向server发送文件信息(包括文件名和文件大小以及MD5值),这个文件信息的大小是预先设定好的,也就是client和server都知道,这样server才能准确判断接收的数据哪些是文件信息哪些是真正的文件。这里用到了struct库对文件信息进行处理。这里的struct类似于c中的结构体,可以把变量转换成具有c结构体形式的字符串。比如我的例子中定义了这样一个struct形式:
它就相当于c中如下结构体:
这个结构体的空间大小是固定的,于是当client按照这个格式发送文件信息的时候,server也以相同的格式接收信息。由于文件名的长度不固定,于是这里我还发送了一个文件名的长度,这样server就可以根据这个长度对fileName进行截取。
然后再发送文件,这里我是用1024B的缓冲区进行接收(最后一次小于或等于1024B)。
过程其实挺简单,先建立两个进程的TCP连接,然后client先向server发送文件信息(包括文件名和文件大小以及MD5值),这个文件信息的大小是预先设定好的,也就是client和server都知道,这样server才能准确判断接收的数据哪些是文件信息哪些是真正的文件。这里用到了struct库对文件信息进行处理。这里的struct类似于c中的结构体,可以把变量转换成具有c结构体形式的字符串。比如我的例子中定义了这样一个struct形式:
HEAD_STRUCT = '128sIq32s'
它就相当于c中如下结构体:
struct{ char fileName[128]; int fileNameSize; long long fileSize; char MD5[32]; }
这个结构体的空间大小是固定的,于是当client按照这个格式发送文件信息的时候,server也以相同的格式接收信息。由于文件名的长度不固定,于是这里我还发送了一个文件名的长度,这样server就可以根据这个长度对fileName进行截取。
然后再发送文件,这里我是用1024B的缓冲区进行接收(最后一次小于或等于1024B)。
***server.py*** import socket import struct import hashlib HOST = 'localhost' PORT = 1307 BUFFER_SIZE = 1024 HEAD_STRUCT = '128sIq32s' # Structure of file head def recv_file(): # Create a TCP socket sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Enable reuse address/port # sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # Bind the socket to the port server_address = (HOST, PORT) # Bind server address sock.bind(server_address) print "Starting server on %s port %s" % server_address # Listen to clients sock.listen(1) print "Waiting to receive from client" client_socket, client_address = sock.accept() print "Socket %s:%d has connect" % client_address # Receive file info info_struct = struct.calcsize(HEAD_STRUCT) file_info = client_socket.recv(info_struct) file_name2, filename_size, file_size, md5_recv = struct.unpack(HEAD_STRUCT, file_info) file_name = file_name2[:filename_size] fw = open(file_name, 'wb') recv_size = 0 print "Receiving data..." while (recv_size < file_size): if(file_size - recv_size < BUFFER_SIZE): file_data = client_socket.recv(file_size - recv_size) recv_size = file_size else: file_data = client_socket.recv(BUFFER_SIZE) recv_size += BUFFER_SIZE fw.write(file_data) fw.close() print "Accept success!" print "Calculating MD5..." fw = open(file_name, 'rb') md5_cal = hashlib.md5() md5_cal.update(fw.read()) print " Recevie MD5 : %s" %md5_recv print "Calculate MD5 : %s" % md5_cal.hexdigest() fw.close() if __name__ == '__main__': recv_file()
***client.py*** import socket import struct import os import time import hashlib HOST = 'localhost' PORT = 1307 BUFFER_SIZE = 1024 FILE_NAME = '001.dmg' # Change to your file FILE_SIZE = os.path.getsize(FILE_NAME) HEAD_STRUCT = '128sIq32s' # Structure of file head def send_file(): # Create a TCP/IP socket sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Connect the socket to the server server_address = (HOST, PORT) #Calculate MD5 print "Calculating MD5..." fr = open(FILE_NAME, 'rb') md5_code = hashlib.md5() md5_code.update(fr.read()) fr.close() print "Calculating success" # Need open again fr = open(FILE_NAME, 'rb') # Pack file info(file name and file size) file_head = struct.pack(HEAD_STRUCT, FILE_NAME, len(FILE_NAME), FILE_SIZE, md5_code.hexdigest()) try: # Connect sock.connect(server_address) print "Connecting to %s port %s" % server_address # Send file info sock.send(file_head) send_size = 0 print "Sending data..." time_start = time.time() while(send_size < FILE_SIZE): if(FILE_SIZE - send_size < BUFFER_SIZE): file_data = fr.read(FILE_SIZE - send_size) send_size = FILE_SIZE else: file_data = fr.read(BUFFER_SIZE) send_size += BUFFER_SIZE sock.send(file_data) time_end = time.time() print "Send success!" print "MD5 : %s" % md5_code.hexdigest() print "Cost %f seconds" % (time_end - time_start) fr.close() sock.close() except socket.errno, e: print "Socket error: %s" % str(e) except Exception, e: print "Other exception : %s" % str(e) finally: print "Closing connect" if __name__ == '__main__': send_file()
注意: - 在使用的时候可把server和client放在两个不同文件夹下,待发文件和client放在同一文件夹下,client.py中的FILE_NAME需要修改成待发的文件名。 - 在某些时候(比如传输大文件)会发生丢包的情况,这时候接收的文件大小会小于发送文件的大小,两个MD5值也会不一样。
相关文章推荐
- python操作mysql数据库
- python vimrc设置
- (转)python之并行任务的技巧
- Python 标准库 urllib2 的使用细节
- python中的StringIO模块
- python学习-----添加IPS到数据文件
- 通过python的ConfigParse模块读写ini配置文件
- 转 -- 使用python的paramiko模块实现ssh与scp功能
- python通过文件头判断文件类型
- Python虚拟环境:Vitualenv
- LeetCode----Binary Search Tree Iterator
- python学习记录之1029
- 记录python数据持久存储的一点问题
- python学习笔记(一)
- 记。。关于python处理表单
- python3 入门 (四) 类与继承
- python3 入门 (四) 类与继承
- Python获取股票历史数据和收盘数据的代码实现
- python 常用库
- python3获取当前目录(转)