在 TCP/IP python 中添加编码和解码的位置
where to add encode and decode in TCP/IP python
我需要 send/receive 从一台笔记本电脑到另一台笔记本电脑的数据,我正在使用 python 3.6
并且这个版本的 python 似乎需要 .encode()
和 .decode()
函数,我使用的是 python 2.7
并且之前没有遇到任何问题,但是现在和 python 3.6
我必须使用这些函数,但我不确定我应该在哪里使用 .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()
但是当我尝试 运行 它时,我在服务器端收到此错误:
sock.send("ERR ")
TypeError: a bytes-like object is required, not 'str'
感谢您的帮助。
你正在发明协议,所以你可以决定什么时候应该解码。一种选择是说基本协议(像 OK 和 ERR 这样的东西总是 ascii 并且可以作为字节进行管理)但是文件名和类似的东西是 utf-8 编码的字符串,需要解码。但是二进制文件呢?您要么需要将流的那部分定义为二进制,要么对内容进行一些 binary-to-ascii 编码。
但它的方式比这更复杂。 TCP是一种流协议。没有任何内容表明 recv
获得了另一方在单个调用中发送的所有内容,或者它以方便的 utf-8 字符边界结束。您不能只是 recv(1024)
并期望获得准确的消息边界。
所以,是时候彻底反思了:定义一个不同的协议。要遵循您现有的模式,您可以使用基于 header 的 ascii,而不是以新行结尾。 header 是一些命令或状态,后跟每个附加参数的字节大小,然后是换行符。后面直接写参数
你可以有这样的命令
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>
以及从输入流中获取提示以了解下一步要做什么的解析器。例如,headers 不包含换行符但以换行符结尾,因此您可以有一个函数读取下一个 header:
def read_header(sock):
hdr = []
while True:
c = sock.recv(1)
if c == "\n":
return ''.join(hdr).encode('ascii')
而 headers 告诉您管道中有多少数据,因此您可以为此设置一个 reader。
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...
我需要 send/receive 从一台笔记本电脑到另一台笔记本电脑的数据,我正在使用 python 3.6
并且这个版本的 python 似乎需要 .encode()
和 .decode()
函数,我使用的是 python 2.7
并且之前没有遇到任何问题,但是现在和 python 3.6
我必须使用这些函数,但我不确定我应该在哪里使用 .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()
但是当我尝试 运行 它时,我在服务器端收到此错误:
sock.send("ERR ")
TypeError: a bytes-like object is required, not 'str'
感谢您的帮助。
你正在发明协议,所以你可以决定什么时候应该解码。一种选择是说基本协议(像 OK 和 ERR 这样的东西总是 ascii 并且可以作为字节进行管理)但是文件名和类似的东西是 utf-8 编码的字符串,需要解码。但是二进制文件呢?您要么需要将流的那部分定义为二进制,要么对内容进行一些 binary-to-ascii 编码。
但它的方式比这更复杂。 TCP是一种流协议。没有任何内容表明 recv
获得了另一方在单个调用中发送的所有内容,或者它以方便的 utf-8 字符边界结束。您不能只是 recv(1024)
并期望获得准确的消息边界。
所以,是时候彻底反思了:定义一个不同的协议。要遵循您现有的模式,您可以使用基于 header 的 ascii,而不是以新行结尾。 header 是一些命令或状态,后跟每个附加参数的字节大小,然后是换行符。后面直接写参数
你可以有这样的命令
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>
以及从输入流中获取提示以了解下一步要做什么的解析器。例如,headers 不包含换行符但以换行符结尾,因此您可以有一个函数读取下一个 header:
def read_header(sock):
hdr = []
while True:
c = sock.recv(1)
if c == "\n":
return ''.join(hdr).encode('ascii')
而 headers 告诉您管道中有多少数据,因此您可以为此设置一个 reader。
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...