从并发TCP服务器下载多个文件:奇怪的结果和"管道错误"

时间:2015-12-07 02:09:06

标签: python sockets tcp concurrency subprocess

我差不多已经完成了一个并发(基于进程的)python TCP服务器,它接受来自客户端的连续命令。客户端可以从服务器下载文件。

截至目前,客户可以通过输入' DL bob.jpg'成功下载光荣的鲍勃罗斯(' bob.jpg')的图像。这将使用str [3:]作为下载命令的输入发送字符串bob.jpg。

客户可以下载图片' bob.jpg'看似无限多次。如果客户端下载文件' Battlefield.mp3',则文件成功下载,但是除非在其间输入了另一个命令(例如DIR),否则下载命令将不再起作用。换句话说:如果客户试图下载' Battlefield.mp3'两次或一次然后' bob.jpg',引发错误。

Battlefield.mp3特别奇怪 - 我将尝试上传另一个mp3并测试一下,看看我是否可以在我的搜索结果中重现和编辑。

我的服务器下载代码的工作方式是:它首先调用socket.send()来发送包含要下载的文件的文件名和文件大小的消息。发送的字符串类似于" bob.jpg | 93174"我的客户端解析它(使用split(" |"))并将它们用作变量。服务器将准确读取文件正在下载的字节数,客户端将写入完全相同的数量(并且还将文件称为相同的文件名)。

客户端

elif data.find("DL") == 0 or data.find("dl") == 0:

        printTime(data)

        fPath = data[3:]

        try:

            file = open(fPath,'rb+')
            print "Opened File: " , file.name
            fSize = os.path.getsize(fPath)
            print "File Size: " , fSize
            strSize = str(fSize)

            seq = (file.name, strSize)
            msg = "|".join(seq)                 
            clientsocket.send(msg)
            fileContent = file.read(fSize)
            clientsocket.send(fileContent)
            file.close()            
            print "Sent and closed file"
        except IOError:
            msg = "Error Opening File"
            print msg
            clientsocket.send(msg)

            continue

服务器

Attempting download using filepath as:  Battlefield.mp3
Download Request Acknowledged from server
Saving file as: Battlefield.mp3
Recieved File Size as: 5410198
Download Complete
Enter Command: dl download.txt
Sending Command: dl download.txt

Attempting download using filepath as:  download.txt
Download Request Acknowledged from server
Traceback (most recent call last):
  File "cli.py", line 74, in <module>
    f = open(dlPath, 'wb+') #Download Target Path
TypeError: file() argument 1 must be encoded string without NULL bytes, not str

客户出局:

Opened File:  Battlefield.mp3
File Size:  5410198
Sent and closed file
Recived  dl download.txt from:  ('127.0.0.1', 34858)  |  2015-12-06 21:05:15.453932
Opened File:  download.txt
File Size:  33
Error Opening File
Process Process-16:
Traceback (most recent call last):
  File "/usr/lib64/python2.6/multiprocessing/process.py", line 232, in _bootstrap
    self.run()
  File "/usr/lib64/python2.6/multiprocessing/process.py", line 88, in run
    self._target(*self._args, **self._kwargs)
  File "serv.py", line 115, in handler
    clientsocket.send(msg)
error: [Errno 32] Broken pipe

服务器输出:

Attempting download using filepath as:  unity.mp3
Download Request Acknowledged from server
Saving file as: unity.mp3
Recieved File Size as: 3985398
Download Complete
Enter Command: dl unity.mp3
Sending Command: dl unity.mp3

Attempting download using filepath as:  unity.mp3
Download Request Acknowledged from server
Saving file as: êa¾è¸Ôq·s¡
                          Recieved File Size as:
õ¯vd22û¥$#P®Gµ7ýÿõ-¶ÛXÝ^m±ÆçìÎÅéM¤Vp6OK¦ÿûDwXVá
                                               +pU«
§n
]a[æ ­ÁL,0
Traceback (most recent call last):
  File "cli.py", line 77, in <module>
    fSize = int(fileSize)
ValueError: invalid literal for int() with base 10: '\x85\x97\xf5\xafvd\x8922\xfb\xa5$#P\xaeG\xa3\x08\xb57\xfd\x93\xff\xf5\x1c-\xb6\xdbX\xdd^\x9d\xec\xef\x08\xea\x95#\xb0\x11\x14\xe3]\x0f\x84I\xa4z\x19f\x89\x19U\x8e\xc5 \xa9\xcfW#U\xdf\xe7Bs\x1d\x18\xdb\xad\xdc\xa092s\xcc\x1d\xd7Y\xccy\x8a\xbb1\x89\xbb]\xd8\xf6a\xce\xfe\xf5\xa2w\x8e\xd9\x98pt\xad\x99\x17\xe6\xab\xb7\xff\x95\x18\xfe\xa9\xb9\xaa\xa8\xaaJSi\xb4"K6\x96\x85\xa9l\x10\xfe\xa3O\xac\xd0'

编辑:

尝试使用不同的mp3会给我一个不同的错误:

{{1}}

似乎发送了实际文件的代码而不是有关文件本身的信息。

1 个答案:

答案 0 :(得分:1)

这里有相当多的代码,但有一件事,正如我怀疑的那样,导致所有这些错误(或者至少是你在编辑中发布的错误 - 服务器错误看起来更像是IPC中的错误)。

所以,这样做

fileInfo = s.recv(1024)
...
fSize = int(fileSize) 
fileContent = s.recv(fSize)
f.write(fileContent)

而不是说您已下载文件(print "Download Complete"),遗憾的是错误。 TCP传输不保留其边界。在一个send中发送1000个字节并不意味着您只需要一个recv来完成所有操作。一条TCP消息在传输过程中可能会碎片化。一些TCP消息可以作为一个到达。唯一保证的是无错误的按顺序交付。

最后一个错误似乎说明了这种情况,你的文件大小与文件的一部分连在一起。

为了克服这种情况,我建议您阅读一些关于TCP和this article about TCP message framing的内容。