初衷
先说一下我写这篇文章的初衷:很多时候,我需要在vmware workstation虚拟机 和 我的物理机 之间传递信息,用U盘作为载体倒来倒去太麻烦。然而,一般来说我会在所有的系统中安装python(当然用C实现更保险,但是就需要.exe和ELF两个文件)。于是,我就想自己搞了一个python脚本,方便在这种“虚拟机和物理机”以及“虚拟机之间”的文件传递。
初次尝试
服务器:接收文件
# -*- coding: cp936 -*-
from socket import *
import struct
import os
ratio_base=0.00
def print_ratio(ratio, delta=1.00):
global ratio_base
if ratio > ratio_base + delta:
ratio_base = ratio_base + delta
print " %4.2f"%ratio,
print "%"
else:
pass
if __name__ == "__main__":
ADDR = ('127.0.0.1',8000)
BUFSIZE = 1024
FILEINFO_SIZE=struct.calcsize('128s32sI8s')
recvSock = socket(AF_INET,SOCK_STREAM)
recvSock.bind(ADDR)
recvSock.listen(5)
conn,addr = recvSock.accept()
fhead = conn.recv(FILEINFO_SIZE)
filename,temp1,filesize,temp2=struct.unpack('128s32sI8s',fhead)
filename = filename.strip('\00') #???
if os.path.isfile(filename):
filename = raw_input("文件已存在,请起一个新名字[default: new_%s] "%filename)
if filename.strip() == "":
filename = 'new_'+filename.strip('\00')
else:
filename = filename.strip('\00')
fp = open(filename,'wb')
restsize = filesize
while True:
if restsize > BUFSIZE:
filedata = conn.recv(BUFSIZE)
else:
filedata = conn.recv(restsize)
if not filedata:
break
fp.write(filedata)
restsize = restsize-len(filedata)
ratio = ( float(filesize) - float(restsize) ) / float(filesize) * 100
print_ratio(ratio)
if restsize == 0:
break
fp.close()
conn.close()
recvSock.close()
print "received all"
客户端:传送文件
# -*- coding: cp936 -*-
from socket import *
import os
import struct
if __name__ == "__main__":
ADDR = ('127.0.0.1',8000)
BUFSIZE = 1024
FILEINFO_SIZE=struct.calcsize('128s32sI8s')
filename = raw_input("file to be sent under this dir: ") #'贫民窟的百万富翁.rmvb'
fhead=struct.pack('128s11I',filename,0,0,0,0,0,0,0,0,os.stat(filename).st_size,0,0)
sendSock = socket(AF_INET,SOCK_STREAM)
sendSock.connect(ADDR)
sendSock.send(fhead)
fp = open(filename,'rb')
while True:
filedata = fp.read(BUFSIZE)
if not filedata:
break
sendSock.send(filedata)
fp.close()
sendSock.close()
print "sent all"
浓缩成一个python脚本
上面代码为了简洁起见,将客户端和服务器代码分离。但是为了部署方便,下面把他们做成一个文件
file_transer.py
# -*- coding: cp936 -*-
from socket import *
import struct
import os
ratio_base=0.00
def print_ratio(ratio, delta=1.00):
global ratio_base
if ratio > ratio_base + delta:
ratio_base = ratio_base + delta
print " %4.2f"%ratio,
print "%"
else:
pass
def client_sender():
print "current directory : ", os.getcwd()
#print os.listdir(os.getcwd())
server_ip = raw_input("receiver's ip : ")
server_port = raw_input("receiver's port : ")
ADDR = (server_ip, int(server_port) )
BUFSIZE = 1024
FILEINFO_SIZE=struct.calcsize('128s32sI8s')
while True:
try:
filename = raw_input("file to be sent under this dir: ") #'贫民窟的百万富翁.rmvb'
fhead=struct.pack('128s11I',filename,0,0,0,0,0,0,0,0,os.stat(filename).st_size,0,0)
sendSock = socket(AF_INET,SOCK_STREAM)
sendSock.connect(ADDR)
sendSock.send(fhead)
fp = open(filename,'rb')
while True:
filedata = fp.read(BUFSIZE)
if not filedata:
break
sendSock.send(filedata)
fp.close()
print "sent"
except:
print "sent error"
sendSock.close()
def server_receiver():
print "my ip : (ipconfig / ifconfig)"
server_port = raw_input("my port : ")
print "waiting for file ..."
ADDR = ("", int(server_port)) #note: DO NOT USE "127.0.0.1"
BUFSIZE = 1024
FILEINFO_SIZE=struct.calcsize('128s32sI8s')
recvSock = socket(AF_INET,SOCK_STREAM)
recvSock.bind(ADDR)
recvSock.listen(5)
while True:
try:
conn,addr = recvSock.accept()
fhead = conn.recv(FILEINFO_SIZE)
filename,temp1,filesize,temp2=struct.unpack('128s32sI8s',fhead)
filename = filename.strip('\00') #???
if os.path.isfile(filename):
filename = raw_input("文件已存在,请起一个新名字[default: new_%s] "%filename)
if filename.strip() == "":
filename = 'new_'+filename.strip('\00')
else:
filename = filename.strip('\00')
fp = open(filename,'wb')
restsize = filesize
while True:
if restsize > BUFSIZE:
filedata = conn.recv(BUFSIZE)
else:
filedata = conn.recv(restsize)
if not filedata:
break
fp.write(filedata)
restsize = restsize-len(filedata)
ratio = ( float(filesize) - float(restsize) ) / float(filesize) * 100
print_ratio(ratio)
if restsize == 0:
break
fp.close()
conn.close()
print filename, " received"
except:
print "receive error"
recvSock.close()
if __name__ == "__main__":
choice = raw_input("send or receive [s/r] : ")
if choice == "s":
client_sender()
print
elif choice == "r":
server_receiver()
print
else:
print "oops..."
有时间再完善下
1. 目前不支持递归传递文件夹
2. 目前不是多线程传输,速度还不够快(不过因为是单机上的传输影响不大)
3. 目前只支持当前文件夹下的传输,最好允许指定路径