【问题标题】:How to finish a socket file transfer in Python?如何在 Python 中完成套接字文件传输?
【发布时间】:2014-11-30 06:12:20
【问题描述】:

我有一个客户端和一个服务器,我需要使用套接字传输一些文件。我可以发送小消息,但是当我尝试发送文件时,问题就开始了......

client.py:

from socket import *
from threading import Thread
import sys
import hashlib

class Client(object):

    ASK_LIST_FILES    = "#001" # 001 is the requisition code to list 
                               # all the files
    ASK_SPECIFIC_FILE = "#002" # 002 is the requisition code to a 
                               # specific file
    SEND_FILE         = "#003" # 003 is the requisition code to send one 
                               # file
    AUTHENTICATION    = "#004" # 004 is the requisition code to user
                               # authentication

    listOfFiles = []

    def __init__(self):
        try:
            self.clientSocket = socket(AF_INET, SOCK_STREAM)
        except (error):
            print("Failed to create a Socket.")
            sys.exit()


    def connect(self, addr):
        try:
            self.clientSocket.connect(addr)
        except (error):
            print("Failed to connect.")
            sys.exit()

        print(self.clientSocket.recv(1024).decode())

    def closeConnection(self):
        self.clientSocket.close()

    def _askFileList(self):
        try:
            data = Client.ASK_LIST_FILES
            self.clientSocket.sendall(data.encode())
            # self._recvFileList()
        except (error):
            print("Failed asking for the list of files.")
            self.closeConnection()
            sys.exit()

        thread = Thread(target = self._recvFileList)
        thread.start()

    def _recvFileList(self):
        print("Waiting for the list...")
        self.listOfFiles = []
        while len(self.listOfFiles) == 0:
            data = self.clientSocket.recv(1024).decode()
            if (data):
                self.listOfFiles = data.split(',')
                if(len(self.listOfFiles) > 0):
                    print (self.listOfFiles)

    def _askForFile(self, fileIndex):

        fileIndex = fileIndex - 1

        try:
            data = Client.ASK_SPECIFIC_FILE + "#" + str(fileIndex)
            self.clientSocket.sendall(data.encode())
        except(error):
            print("Failed to ask for an specific file.")
            self.closeConnection()
            sys.exit()

        self._downloadFile(fileIndex)

    def _downloadFile(self, fileIndex):
        print("Starting receiving file")
        f = open("_" + self.listOfFiles[fileIndex], "wb+")
        read = self.clientSocket.recv(1024)
        # print(read)
        # f.close
        while len(read) > 0:
            print(read)
            f.write(read)
            f.flush()
            read = self.clientSocket.recv(1024)
        f.flush()
        f.close()
        self.closeConnection()

server.py

from socket import *
from threading import Thread
import sys
import glob

class Server(object):

    def __init__(self):
        try:
            self.serverSocket = socket(AF_INET, SOCK_STREAM)
        except (error):
            print("Failed to create a Socket.")
            sys.exit()

    def connect(self, addr):
        try:
            self.serverSocket.bind(addr)
        except (error):
            print ("Failed on binding.")
            sys.exit()

    def closeConnection(self):
        self.serverSocket.close()

    def waitClients(self, num):
        while True:
            print("Waiting for clients...")
            self.serverSocket.listen(num)
            conn, addr = self.serverSocket.accept()
            print("New client found...")
            thread = Thread(target = self.clientThread, args = (conn,))
            thread.start()

    def clientThread(self, conn):
        WELCOME_MSG = "Welcome to the server"
        conn.send(WELCOME_MSG.encode())
        while True:
            data = conn.recv(2024).decode()
            if(data):
                # print(data)
                # reply = 'OK: ' + data
                # conn.sendall(reply.encode())
                if(data == "#001"):
                    listOfFiles = self.getFileList()
                    strListOfFiles = ','.join(listOfFiles)
                    self._sendFileList(strListOfFiles, conn)
                else:
                    dataCode = data.split('#')
                    print(dataCode)
                    if(dataCode[1] == "002"):
                        print("Asking for file")
                        self._sendFile(int(dataCode[2]), conn)
                    if(dataCode[1] == "003"):
                        print("Pedido de login")
                        if self._authentication(dataCode[2]):
                            conn.send("OK".encode())
                            # self._recvFile(conn)
                        else:
                            conn.send("FAILED".encode())



    def _sendFile(self, fileIndex, conn):
        listOfFiles = self.getFileList()
        print(fileIndex)
        print(listOfFiles[fileIndex])
        f = open(listOfFiles[fileIndex], "rb")
        read = f.read(1024)
        while len(read) > 0:
            conn.send(read)
            read = f.read(1024)          
        f.close()

    def _sendFileList(self, strList, conn):
        try:
            conn.sendall(strList.encode())
        except (error):
            print("Failed to send list of files.")

    def getFileList(self):
        return glob.glob("files/*")

当我尝试从服务器获取文件时,我可以传输所有内容,但连接永远不会结束。我的代码怎么了?

【问题讨论】:

    标签: python sockets tcp file-transfer


    【解决方案1】:

    首先,您在这里遇到了使用 TCP 最常见的错误:假设在单个 send() 中发送的所有数据将在单个 recv() 中得到相同的数据。这对 TCP 来说是不正确的,因为它是 octet 流,而不是消息流。您的代码只能在理想(实验室)条件下工作,并且在现实世界的使用中可能会神秘地失败。您应该明确地在 TCP 流中创建消息边界,或者切换例如到 SCTP。后者现在几乎在任何地方都可用,并通过网络连接保持消息边界。

    您的第二个错误与第一个错误直接相关。发送文件时,您不提供文件已完成的任何明确标记。因此,客户永远等待。您可能会尝试关闭服务器连接以显示文件已完成,但在这种情况下客户端将无法区分真正的文件结束和连接丢失;此外,该连接不能再用于进一步的命令。您可以选择以下方式之一:

    • 为文件内容加上长度前缀。在这种情况下,客户端将知道该文件应接收多少字节。
    • 以块序列的形式发送文件内容,在每个块前面加上它的长度(仅适用于 TCP)并标记该块是否是最后一个(对于两种传输方式)。或者,可以发送不带数据的特殊标记“EOF”。

    同样,控制消息及其响应应提供不能出现在此类消息中的长度前缀或终止符。

    当你完成这个开发后,你会看看 FTP 和 HTTP;两者都解决了我在此处描述的所有问题,但方式主要不同。

    【讨论】:

      猜你喜欢
      • 2011-10-13
      • 2015-05-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-18
      相关资源
      最近更新 更多