使用 VB.Net 通过 TCP 发送文件并使用 Python3 中的套接字接收文件时出现文件编码错误。6
File Encoding error while sending file via TCP with VB.Net and receiving with Socket in Python3.6
我在 VB.Net 中有一个用 ZipFile.CreateFromDirectory("temp/", "payload.zip", CompressionLevel.Optimal, True)
创建的 zip 文件,我发送到我的 python 服务器:
Dim payload() As Byte = System.Text.Encoding.UTF8.GetBytes(System.Convert.ToBase64String(System.IO.File.ReadAllBytes("payload.zip")))
Dim payloadstr As String = byteArrToString(payload)
Dim client As New TcpClient("192.168.0.160", 42069)
Dim PayloadWriter As New StreamWriter(client.GetStream())
PayloadWriter.Write(payloadstr)
PayloadWriter.Flush()
PayloadWriter.Close()
client.Close()
byteArrToString()
函数如下所示:
Public Function byteArrToString(ByVal arr() As Byte) As String
Return System.Text.Encoding.Unicode.GetString(arr)
End Function
在 python 服务器端,我的代码如下所示:
import socket # Import socket module
import random,string,io
def randomString(stringLength=10):
letters = string.ascii_lowercase
return ''.join(random.choice(letters) for i in range(stringLength))
s = socket.socket() # Create a socket object
host = "192.168.0.160" # Define Hostname
port = 42069 # Reserve a port for your service.
s.bind((host, port)) # Bind to the port
s.listen(5) # Now wait for client connection.
irName = randomString(10) + ".zip"
ir = io.open(irName,"wb")
print ("Listening now")
while True:
c, addr = s.accept() # Establish connection with client.
print ('Got connection from', addr)
print ("Receiving Data...")
print ("Writing as " + irName)
l = c.recv(4096)
while (l):
ir.write(l)
l = c.recv(4096)
ir.close()
c.close()
print ("Done receiving")
不知何故,我在服务器端收到的 Payload.zip 的大小是 Windows 中 Payload.zip 的两倍,系统拒绝将其识别为有效的 ZIP 文件。我做错了什么?
解释
你在 VB.NET 端的字符串编码上搞砸了很多,在这种情况下你真的不应该也不需要这样做。为了帮助您了解正在发生的事情,下面概述了您的代码现在的作用:
VB.NET
- 将压缩文件作为字节数组读入内存。
- 将字节数组转换为 Base64 编码的字符串。
- 将Base64字符串直接转换为字节数组(注意:这与步骤1中的数组不同)。
- 再次将该字节数组转换回,但这次使用UTF-16/Unicode编码。
- 使用
StreamWriter
将其发送到 Python 端,这可能会或可能不会将 BOM 添加到流的开头。
Python
- 接收来自VB.NET的数据。
- 将其写入文件。
在 Python 中你没有做任何事情来逆转你在 VB.NET 代码中采取的步骤,所以这就是数据不同的原因。
从第 3 步开始,您还使用了一个完全不同的字节数组,它不再表示压缩文件的 raw 数据,而是它的 Base64 编码版本.一般来说,Base64 通常会将数据大小增加 1.5 倍左右,这就是您看到大小增加的原因。
严格来说,在这种情况下,您 需要在 Python 端执行以下操作来反转过程:
- 取所有接收到的数据(在Python中是一个字符串)。
- 从 Base64 解码。
- 写入文件。
编码之间的切换(步骤 4 中的 UTF-8 到 16/Unicode)在数据本身方面不应该做太多,因为它主要影响字符串的显示方式,所以这不是你真正需要的东西需要反转。
答案
我猜你在 VB.NET 端做所有与字符串相关的工作的原因是因为 Python 套接字将其数据作为字符串处理。但是您应该知道,在后台(即使在 Python 中)字符串是并且永远是字节数组,无论如何。
我理解这种混乱,而且我以前见过很多次,但编码主要只是一种存储 and/or 显示文本的方式。丢失数据的唯一方法是尝试使用不兼容的编码来显示它。但在这种情况下,您不是在处理文本,而是在处理 原始数据 。因此,只要您不试图通过通过字符串来显示或操纵它,就根本不需要转换它。
你(应该)需要做的就是将File.ReadAllBytes()
返回的字节数组直接发送给Python.
Dim payload() As Byte = System.IO.File.ReadAllBytes("payload.zip")
Using client As New TcpClient("192.168.0.160", 42069)
Using stream As NetworkStream = client.GetStream()
stream.Write(payload)
End Using
End Using
Using
/End Using
块负责为您关闭和处置对象。
我在 VB.Net 中有一个用 ZipFile.CreateFromDirectory("temp/", "payload.zip", CompressionLevel.Optimal, True)
创建的 zip 文件,我发送到我的 python 服务器:
Dim payload() As Byte = System.Text.Encoding.UTF8.GetBytes(System.Convert.ToBase64String(System.IO.File.ReadAllBytes("payload.zip")))
Dim payloadstr As String = byteArrToString(payload)
Dim client As New TcpClient("192.168.0.160", 42069)
Dim PayloadWriter As New StreamWriter(client.GetStream())
PayloadWriter.Write(payloadstr)
PayloadWriter.Flush()
PayloadWriter.Close()
client.Close()
byteArrToString()
函数如下所示:
Public Function byteArrToString(ByVal arr() As Byte) As String
Return System.Text.Encoding.Unicode.GetString(arr)
End Function
在 python 服务器端,我的代码如下所示:
import socket # Import socket module
import random,string,io
def randomString(stringLength=10):
letters = string.ascii_lowercase
return ''.join(random.choice(letters) for i in range(stringLength))
s = socket.socket() # Create a socket object
host = "192.168.0.160" # Define Hostname
port = 42069 # Reserve a port for your service.
s.bind((host, port)) # Bind to the port
s.listen(5) # Now wait for client connection.
irName = randomString(10) + ".zip"
ir = io.open(irName,"wb")
print ("Listening now")
while True:
c, addr = s.accept() # Establish connection with client.
print ('Got connection from', addr)
print ("Receiving Data...")
print ("Writing as " + irName)
l = c.recv(4096)
while (l):
ir.write(l)
l = c.recv(4096)
ir.close()
c.close()
print ("Done receiving")
不知何故,我在服务器端收到的 Payload.zip 的大小是 Windows 中 Payload.zip 的两倍,系统拒绝将其识别为有效的 ZIP 文件。我做错了什么?
解释
你在 VB.NET 端的字符串编码上搞砸了很多,在这种情况下你真的不应该也不需要这样做。为了帮助您了解正在发生的事情,下面概述了您的代码现在的作用:
VB.NET
- 将压缩文件作为字节数组读入内存。
- 将字节数组转换为 Base64 编码的字符串。
- 将Base64字符串直接转换为字节数组(注意:这与步骤1中的数组不同)。
- 再次将该字节数组转换回,但这次使用UTF-16/Unicode编码。
- 使用
StreamWriter
将其发送到 Python 端,这可能会或可能不会将 BOM 添加到流的开头。
Python
- 接收来自VB.NET的数据。
- 将其写入文件。
在 Python 中你没有做任何事情来逆转你在 VB.NET 代码中采取的步骤,所以这就是数据不同的原因。
从第 3 步开始,您还使用了一个完全不同的字节数组,它不再表示压缩文件的 raw 数据,而是它的 Base64 编码版本.一般来说,Base64 通常会将数据大小增加 1.5 倍左右,这就是您看到大小增加的原因。
严格来说,在这种情况下,您 需要在 Python 端执行以下操作来反转过程:
- 取所有接收到的数据(在Python中是一个字符串)。
- 从 Base64 解码。
- 写入文件。
编码之间的切换(步骤 4 中的 UTF-8 到 16/Unicode)在数据本身方面不应该做太多,因为它主要影响字符串的显示方式,所以这不是你真正需要的东西需要反转。
答案
我猜你在 VB.NET 端做所有与字符串相关的工作的原因是因为 Python 套接字将其数据作为字符串处理。但是您应该知道,在后台(即使在 Python 中)字符串是并且永远是字节数组,无论如何。
我理解这种混乱,而且我以前见过很多次,但编码主要只是一种存储 and/or 显示文本的方式。丢失数据的唯一方法是尝试使用不兼容的编码来显示它。但在这种情况下,您不是在处理文本,而是在处理 原始数据 。因此,只要您不试图通过通过字符串来显示或操纵它,就根本不需要转换它。
你(应该)需要做的就是将File.ReadAllBytes()
返回的字节数组直接发送给Python.
Dim payload() As Byte = System.IO.File.ReadAllBytes("payload.zip")
Using client As New TcpClient("192.168.0.160", 42069)
Using stream As NetworkStream = client.GetStream()
stream.Write(payload)
End Using
End Using
Using
/End Using
块负责为您关闭和处置对象。