繁体   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