我差不多已经完成了一个并发(基于进程的)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}}
似乎发送了实际文件的代码而不是有关文件本身的信息。
答案 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的内容。