pythonネットワーク(二、転送ファイル)

7587 ワード

初志
まず、私がこの文章を書いた初心を話します.多くの場合、vmware workstation仮想マシンと私の物理マシンの間で情報を伝える必要があります.Uディスクをキャリアとして逆さまにするのは面倒です.しかし、一般的にはすべてのシステムにpythonをインストールします(もちろんCで実現するのはもっと安全ですが、.exeとELFの2つのファイルが必要です).そこで、私は自分で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. 現在は現在のフォルダでの転送のみがサポートされていますので、パスの指定を許可したほうがいいです.