我需要从一台笔记本电脑向另一台笔记本电脑发送/接收数据,我正在使用python 3.6
,看起来这个版本的python需要.encode()
和.decode()
函数,我正在使用python 2.7
而我之前没有遇到麻烦,但是现在和python 3.6
我都要使用这些函数,但是我不确定我应该在哪里使用{{1命令您将在我的服务器文件和我的客户端文件下面找到
服务器文件:
.decode()
这是我的客户档案:
import socket
import threading
import os
def RetrFile(name, sock):
filename = sock.recv(1024)
filename.decode()
if os.path.isfile(filename):
sock.send("EXISTS " + str(os.path.getsize(filename)))
userResponse = sock.recv(1024)
if userResponse[:2] == 'OK':
with open(filename, 'rb') as f:
bytesToSend = f.read(1024)
sock.send(bytesToSend)
while bytesToSend != "":
bytesToSend = f.read(1024)
sock.send(bytesToSend)
else:
sock.send("ERR ")
sock.close()
def MainServer():
host = '172.16.1.2' #my IP adress
port = 5000
s = socket.socket()
s.bind((host,port))
s.listen(5)
print ("Server Started.")
while True:
c, addr = s.accept()
print ("client connected ip:<" + str(addr) + ">")
t = threading.Thread(target=RetrFile, args=("RetrThread", c))
t.start()
s.close()
if __name__ == '__main__':
MainServer()
但是当我尝试运行它时,我在服务器端遇到了这个错误:
import socket
def MainClient():
host = '172.16.1.2'
port = 5000
s = socket.socket()
s.connect((host, port))
filename = input("Filename? -> ")
byt=filename.encode()
if byt != 'q':
s.send(byt)
data = s.recv(1024)
if data[:6] == 'EXISTS':
filesize = len(data[6:])
message = input("File exists, " + str(filesize) +"Bytes, download? (Y/N)? -> ")
if message == 'Y':
s.send("OK")
f = open('new_'+filename, 'wb')
data = s.recv(1024)
totalRecv = len(data)
f.write(data)
while totalRecv < filesize:
data = s.recv(1024)
totalRecv += len(data)
f.write(data)
print ("{0:.2f}".format((totalRecv/float(filesize))*100)+ "% Done")
print ("Download Complete!")
f.close()
else:
print ("File Does Not Exist!")
s.close()
if __name__ == '__main__':
MainClient()
感谢您的帮助。
答案 0 :(得分:2)
您正在发明协议,以便决定何时解码。一种选择是说基本协议(像OK和ERR这样的东西总是ascii并且可以作为字节管理)但文件名和类似的东西是utf-8编码的字符串,需要解码。但是二进制文件怎么样?您需要将流的该部分定义为二进制或对内容执行二进制到ascii编码。
但它的方式比那更复杂。 TCP是一种流协议。没有任何东西可以说recv
获取对方在一次通话中发送的所有内容,或者它以方便的utf-8字符边界结束。您不能只是recv(1024)
并希望得到准确的邮件边界。
所以,时间进行彻底的重新思考:定义一个不同的协议。要遵循现有模式,您可以使用基于ascii的标题,而不是以新行结尾。标题是一些命令或状态,后跟每个附加参数的字节大小,后跟换行符。之后将直接写入参数。
你可以拥有像
这样的命令STAT <sizeof utf-8 encoded file name>\n<utf-8-encoded-filename>
EXISTS ascii-encoded-size\n
DOWNLOAD <sizeof utf-8 encoded file name>\n<utf-8-encoded-filename>
从输入流中获取提示以获知下一步操作的解析器。例如,标题不包含换行符,但以换行符结尾,因此您可以使用读取下一个标题的函数:
def read_header(sock):
hdr = []
while True:
c = sock.recv(1)
if c == "\n":
return ''.join(hdr).encode('ascii')
标题会告诉您管道中有多少数据,因此您可以拥有一个阅读器。
def read_chunk(sock, size, encoding=None):
buf = io.bytesIO()
while size:
tmp = sock.recv(min(size, 4096))
if not tmp:
raise OSError("Unexpected end of stream")
buf.write(tmp)
size -= len(tmp)
if encoding:
return buf.getvalue().encode(encoding)
else:
return buf.getvalue()
读取流将是
while True:
hdr = read_header(sock)
# try commands
m = re.match(b"STAT (\d+)", hdr)
if m:
stat_size = int(m.group(1))
file_name = read_chunk(sock, stat_size, 'utf-8')
# do the stat work...
continue
m = re.match(b"DOWNLOAD (\d+)", hdr)
etc...