簡體   English   中英

Python文件服務器僅在運行一個線程的情況下工作

[英]Python File Server Only Works with One Thread Running

我已經使用套接字和線程在python上制作了文件服務器。 該程序應該允許客戶端從服務器上載和下載文件。

當只有一個線程正在運行時,該程序可以完美運行,但是當兩個線程都在運行時,服務器在嘗試上傳文件時會出錯,而在嘗試下載程序時,客戶端輸入“ Y”以啟動該程序后,它只會停止執行任何操作。下載。

這是客戶端的代碼:

import socket
import os

def DownloadFile(s, host, port):
    s.connect((host, port))
    s.send(str.encode('DNLD'))
    filename = input('Filename? ->')
    if filename != 'q':
        s.send(str.encode(filename))
        data = s.recv(2048).decode('UTF-8')
        if data[:6] == 'EXISTS':
            filesize = data[6:]
            message = input('File Exists, ' + str(filesize) + ' Bytes. Download? (Y/N) ->')
            if message == 'Y' or message == 'y':
                s.send(str.encode('OK'))
                f = open('copy of '+filename, 'wb')
                data = s.recv(2048)
                totalRecv = len(data)
                f.write(data)
                while totalRecv < int(filesize):
                    data = s.recv(2048)
                    totalRecv += len(data)
                    f.write(data)
                    print('{}'.format(round((totalRecv/float(filesize))*100),2)+'% Complete')
                print('Download Complete!')
                s.close()

        else:
            print('File does not exist')
            s.close()
    Main()

def UploadFile(s, host, port):
    s.connect((host, port))
    s.send(str.encode('UPLD'))
    filename = input('Filename? ->')
    if os.path.isfile(filename):
        filesize = os.path.getsize(filename)
        filesize = str(filesize)
        s.send(str.encode('EXISTS ' + filename))
        s.send(str.encode(filesize))
        ready = input('Ready to upload. Proceed? (Y/N) ->')
        if ready == 'Y' or ready == 'y':
            s.send(str.encode('OK'))
            with open(filename, 'rb') as f:
                bytesToSend = f.read(2048)
                s.send(bytesToSend)
                while bytesToSend != '':
                    bytesToSend = f.read(2048)
                    s.send(bytesToSend)
                s.close()
    else:
        print('File does not exist.')
        s.close()
    Main()

def Main(): 
    host = '127.0.0.1'
    port = 10000
    s = socket.socket()
    while True:
        choice = int(input('Please enter your choice:\n\n1. Upload a file to the server.\n2. Download a file from the server\n3. Quit.\n\n->'))
        if choice == 1:
            UploadFile(s, host, port)
            break
        elif choice == 2:
            DownloadFile(s, host, port)
            break
        elif choice == 3:
            s.close()
            break
        else:
            print('Please enter a valid choice.')

if __name__ == '__main__':
    Main()

這是服務器的代碼:

import socket
import threading
import os

def SendFile(name, s):
    check = s.recv(2048).decode('UTF-8')
    if check == 'DNLD':
        filename = s.recv(2048)
        if os.path.isfile(filename):
            send = os.path.getsize(filename)
            send = str(send)
            s.send(str.encode('EXISTS ' + send))
            userResponse = s.recv(2048)
            userResponse = userResponse.decode('UTF-8')
            if userResponse[:2] == 'OK':
                with open(filename, 'rb') as f:
                    bytesToSend = f.read(2048)
                    s.send(bytesToSend)
                    while bytesToSend != '':
                        bytesToSend = f.read(2048)
                        s.send(bytesToSend)
            else:
                s.send(str.encode('ERR'))

    s.close()

def ReceiveFile(name, s):
    check = s.recv(2048).decode('UTF-8')
    if check == 'UPLD':
        data = s.recv(2048).decode('UTF-8')
        if data[:6] == 'EXISTS':
            filename = data[6:]
            data = s.recv(2048).decode('UTF-8')
            filesize = data
            userResponse = s.recv(2048)
            userResponse = userResponse.decode('UTF-8')
            if userResponse[:2] == 'OK':
                f = open('copy of '+filename, 'wb')
                data = s.recv(2048)
                totalRecv = len(data)
                f.write(data)
                while totalRecv < int(filesize):
                    data = s.recv(2048)
                    totalRecv += len(data)
                    f.write(data)
                print('Download Complete!')

def Main():
    host = '127.0.0.1'
    port = 10000
    s = socket.socket()
    s.bind((host, port))
    s.listen(5)
    print('Server Started')

    while True:
        c, addr = s.accept()
        print('Client Connected: ' + str(addr))
        Send = threading.Thread(target=SendFile, args=('sendThread', c))
        Send.start()
        Receive = threading.Thread(target=ReceiveFile, args=('retrThread', c))
        Receive.start()

    s.close()

if __name__ == '__main__':
    Main()

如果我要注釋掉Send.start()或Receive.start(),那么任何未注釋掉的線程都可以正常工作。

這是嘗試在兩個線程都運行的情況下上載文件時服務器中給出的錯誤:

Exception in thread Thread-2:
Traceback (most recent call last):
  File "C:\Python34\lib\threading.py", line 920, in _bootstrap_inner
    self.run()
  File "C:\Python34\lib\threading.py", line 868, in run
    self._target(*self._args, **self._kwargs)
  File "(file location)", line 28, in ReceiveFile
    check = s.recv(2048).decode('UTF-8')
OSError: [WinError 10038] An operation was attempted on something that is not a socket

這是兩個線程同時運行時嘗試下載文件時客戶端的輸出:

Please enter your choice:

1. Upload a file to the server.
2. Download a file from the server
3. Quit.

->2
Filename? ->cat.jpg
File Exists,  10634 Bytes. Download? (Y/N) ->Y

輸入Y后沒有其他反應。

如果有人知道出了什么問題,我將非常感謝您的幫助。

那不是io和線程的工作方式。 在這里,您有2個線程與同一輸入數據競爭。 一個人將獲得第一個數據包,無論是否為它,然后另一個線程有可能吞噬以下一個數據包=>第一個將永遠看不到它!

您可以將對話的處理委派給一個線程,但可以委派給一個線程,一旦它確定了請求,該線程將調用發送或接收函數。

這還不是全部。 TCP是協議。 數據包可以沿着連接的任何部分(發送者,接收者和任何網關)拆分或重新組裝。 因此,您應該使用定界符來告知對等方名稱或命令(如果已完成)。 優良作法建議在發送二進制數據時傳遞大小,在此再次讓對等方知道數據何時完成。

套接字世界是您旅途中的好運;-)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM