Python套接字编程:将文件从客户端上传到服务器

时间:2018-11-17 17:58:33

标签: python sockets unix filesystems virtual-machine

我正在寻找一些有关我的python套接字编程的帮助。
目标:将文件从客户端上传到服务器。我当前的设置涉及两个虚拟机,分别是服务器和客户端,分别位于其中的.py文件。 server.py和client.py。我遇到的问题是,当我选择上载选项时,输出显示为“文件上载...。文件成功上载”,但是当我在服务器端查看时,该文件不存在-也没有我收到一个错误。当我发送文件上传时,服务器显示它已接收到连接。我目前所拥有的是……任何帮助将不胜感激。

Server.py

import config, protocol
import os
from socket import *
import threading
import time
import sys


class server():

    # Constructor: load the server information from config file
    def __init__(self):
        self.port, self.path, self.path2 = config.config().readServerConfig()

    # function to receive file data from client 
    def receiveFile(self, serverSocket, fileName):
        serverSocket.connect()
        serverSocket.send(protocol.prepareMsg(protocol.HEAD_UPLOAD, fileName))
        with open(fileName, 'wb') as f:
            print('file incoming...')
            while True:
                print('receiving data...')
                data = serverSocket.recv(1024)
                if not data:
                    break
                f.write(data)
        print(fileName + " has been Received!")
        serverSocket.close()


    # Main function of server, start the file sharing service
    def start(self):
        serverPort=self.port
        serverSocket=socket(AF_INET,SOCK_STREAM)
        serverSocket.bind(('',serverPort))
        serverSocket.listen(20)
        print('The server is ready to receive')
        while True:
            connectionSocket, addr = serverSocket.accept()
            print("**Conn. to ", addr)
            dataRec = connectionSocket.recv(1024)
            header,msg= protocol.decodeMsg(dataRec.decode()) # get client's info, parse it to header and content
            # Main logic of the program, send different content to client according to client's requests
            if(header== protocol.HEAD_REQUEST):
                self.listFile(connectionSocket)
            elif(header == protocol.HEAD_DOWNLOAD):
                self.sendFile(connectionSocket, self.path+"/"+msg)
            elif(header == protocol.HEAD_UPLOAD):
                self.receiveFile(connectionSocket, self.path2+"/"+msg)
            else:
                connectionSocket.send(protocol.prepareMsg(protocol.HEAD_ERROR, "Invalid Message"))
            connectionSocket.close()






def main():
    s=server()
    s.start()

main()


Client.py

import config, protocol
from socket import *
import threading
import time
import os
import sys

class client:

    fileList=[] # list to store the file information
    uploadFileList = []

    #Constructor: load client configuration from config file
    def __init__(self):
        self.serverName, self.serverPort, self.clientPort, self.downloadPath, self.uploadPath = config.config().readClientConfig()

    # Function to produce user menu 
    def printMenu(self):
        print("Welcome to simple file sharing system!")
        print("Please select operations from menu")
        print("--------------------------------------")
        print("3. Upload File")
        print("5. Quit")

    # Function to get user selection from the menu
    def getUserSelection(self):       
        ans=0
        # only accept option 1-4
        while ans>5 or ans<1:
            self.printMenu()
            try:
                ans=int(input())
            except:
                ans=0
            if (ans<=5) and (ans>=1):
                return ans
            print("Invalid Option")

    # Build connection to server
    def connect(self):
        serverName = self.serverName
        serverPort = self.serverPort
        clientSocket = socket(AF_INET, SOCK_STREAM)
        clientSocket.connect((serverName,serverPort))
        return clientSocket

    def getUploadFileList(self):
        self.uploadFileList = os.listdir(self.uploadPath)

    def printUploadFileList(self):
        count = 0
        for f in self.uploadFileList:
            count += 1
            print('{:<3d}{}'.format(count, f))

    def selectUploadFile(self):
        if (len(self.uploadFileList)==0):
            self.getUploadFileList()
        ans=-1
        while ans<0 or ans>len(self.uploadFileList)+1:
            self.printUploadFileList()
            print("Please select the file you want to upload from the list (enter the number of files):")
            try:
                ans=int(input())
            except:
                ans=-1
            if (ans>0) and (ans<len(self.uploadFileList)+1):
                return self.uploadFileList[ans-1]
            print("Invalid number")

    def uploadFile(self, fileName):
        mySocket=self.connect()
        mySocket.send(protocol.prepareMsg(protocol.HEAD_UPLOAD, fileName))
        f = open(fileName, 'rb')
        l = f.read(1024)  # each time we only send 1024 bytes of data
        while (l):
            print('File uploading...')
            mySocket.sendall(l)
            l = f.read(1024)
        f.close()
        print("File Uploaded Successfully!")


    # Main logic of the client, start the client application
    def start(self):
        opt=0
        while opt!=5:
            opt=self.getUserSelection()
            if opt==3:
                self.uploadFile(self.selectUploadFile())
            else:
                pass


def main():
    c=client()
    c.start()


main()


我已经在协议文件中定义了我拥有的模块...

Protocol.py

HEAD_LIST='LST'
HEAD_REQUEST='REQ'
HEAD_DOWNLOAD='DLD'
HEAD_UPLOAD='ULD'
HEAD_FILE='FIL'
HEAD_ERROR='ERR'

# we prepare the message that are sent between server and client as the header + content
def prepareMsg(header, msg):
    return (header+msg).encode()

def prepareFileList(header,fList):
    '''
    function to prepare file list to msg
    '''
    msg=header
    for i in range(len(fList)):
        if (i==len(fList)-1):
            msg+=fList[i]
        else:
            msg+=fList[i]+','
    return msg.encode()

# Decode the received message, the first three letters are used as protocol header
def decodeMsg(msg):
    if (len(msg)<=3):
        return HEAD_ERROR, 'EMPTY MESSAGE'
    else:
        return msg[0:3],msg[3:len(msg)]

我还定义了我的配置文件,如下所示...
Config.py

class config:
    #define header
    server_port='SERVER_PORT'
    path="PATH"
    path2="PATH2"
    server="SERVER"
    client_port="CLIENT_PORT"
    download="DOWNLOAD"
    upload="UPLOAD"
    serverConfig="server.config"
    clientConfig="client.config"

    def __init__(self):
        pass
    def readServerConfig(self):
        try:
            with open(self.serverConfig,'r') as f:
                serPort=0
                sharePath=""
                sharePath2=""
                for l in f:
                    sub=l.strip().split("=")
                    if(sub[0]==self.server_port):
                        serPort=int(sub[1])
                    elif(sub[0]==self.path):
                        sharePath=sub[1]
                    elif (sub[0] == self.path2):
                        sharePath2 = sub[1]


                    else:
                        pass
                return serPort, sharePath, sharePath2
        except:
            print(Exception.message())




    def readClientConfig(self):
        '''
        This function read client configuration file, return four values
        @return: serverName
        @return: serverPort
        @return: clientPort
        @return: downloadPath
        '''
        try:
            with open(self.clientConfig,'r') as f:
                serPort=0
                serName=""
                clientPort=0
                downPath=""
                upPath=""
                for l in f:
                    sub=l.strip().split("=")
                    if(sub[0]==self.server_port):
                        serPort=int(sub[1])
                    elif(sub[0]==self.server):
                        serName=sub[1]
                    elif(sub[0]==self.client_port):
                        clientPort=sub[1]   
                    elif(sub[0]==self.download):
                        downPath=sub[1]
                    elif(sub[0]==self.upload):
                        upPath=sub[1]
                    else:
                        pass  
                return serName, serPort, clientPort, downPath, upPath
        except:
            print(Exception.message())

# The function to test the configuration class           
def test():
    conf=config()
    client=conf.readClientConfig()
    server=conf.readServerConfig()
    print(client)
    print(server)

上面的代码将返回文件列表,我可以选择我要上传的文件,并且代码将声明其完整,但是我无法在服务器上找到文件。我在两台计算机的目录路径中都设置了测试文件。另外,我的server.config和client.config文件设置为:
server.config

SERVER_PORT=12007
PATH=/root/serverFiles
PATH2=/root/files


client.config

SERVER=192.168.10.1
SERVER_PORT=12007
CLIENT_PORT=12006
DOWNLOAD=/root/Downloads
UPLOAD=/root/Upload

1 个答案:

答案 0 :(得分:1)

您的uploadFile()方法将connect()发送到服务器,然后sendall()发送文件内容(以1024字节为块)。

另一方面,

您的服务器将接收前1024个字节(即文件 内容的前1024个字节),并根据协议进行解释,查看文件的前三个字节 文件 内容。但是,客户端永远不会像服务器期望的那样发送protocol.HEAD_UPLOAD

(顺便说一句,我真的很推荐您PEP8代码,并避免使用*导入。它使代码更易于阅读,从而对您有所帮助。)