【发布时间】:2021-12-19 18:46:00
【问题描述】:
我有一个 android 应用程序,它使用 DataOutputStream 通过套接字将图像从画廊发送到 Python 服务器,以写入客户端应用程序中的套接字。图像从外部存储目录加载并在发送前缓冲。图像由服务器接收并写入磁盘内存。当我尝试打开图像时,它给了我:“读取图像文件的致命错误。不是 PNG”。然而,图像占用的实际图像大小为 430 KiB。当我打印接收到的数据时,它会给我一些看起来像原始图像的东西:
b'\x97\xa7p\xc0\x04\xfbv\xf6\\\xed\x8a\xe9^\xbf\xa4p9\xae\x8eu:N\xb5\x8e\xcc\x06\xa6\xf1\tyL\xf3.^W\xb5RR\xd3)\x7fS\xf3\x8f\x1b\xc6\xf8\xa7\x9b\xf5\xb8\xc3f\xa9\xdf\xa1\xbd\xaa\xbeS\xbc\x84zt\xedT\xbfn|I\xfb\x0e\xfb\xae6\x18sS\x9b\x9e\xd8\xff\xc4>\xaf\xeb\xba\xbe>{\xe2\x87~\xe8\x87~\xe8\x87~\xe8\x87~\xe8\x87~\xe8\x87~\xe8\x87~\xe8\x87~\xe8\x87~\xe8\x87~\xe8\x87\xfe\xbf\xa4\xff\x07\xe5\x9f\xdc\xd5\xe2d\xc5\xcb\x00\x00\x00\x00IEND\xaeB`\x82'
b''
文字比较长,但是我删了..
从目录加载图像并写入套接字的客户端代码:
class send extends AsyncTask<Void, Void, Void> {
Socket s; //Socket Variable
@Override
protected Void doInBackground(Void... params) {
try {
s = new Socket("192.168.0.14", 9999);
String image = getLatestFilefromDir("/storage/emulated/0/DCIM");
File file = new File(image);
try (InputStream is = new BufferedInputStream(new FileInputStream(file));
DataOutputStream dos = new DataOutputStream(s.getOutputStream())) {
dos.writeLong(file.length());
int val;
while ((val = is.read()) != -1) {
dos.write(val);
}
dos.flush();
} catch (IOException e) {
e.printStackTrace();
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
private String getLatestFilefromDir(String dirPath){
File dir = new File(dirPath);
File[] files = dir.listFiles();
if (files == null || files.length == 0) {
return null;
}
File lastModifiedFile = files[0];
for (int i = 1; i < files.length; i++) {
if (lastModifiedFile.lastModified() < files[i].lastModified()) {
lastModifiedFile = files[i];
}
}
return lastModifiedFile.toString();
}
Python 服务器:
#Imports modules
import socket
import datetime
date_string = datetime.datetime.now().strftime("%Y-%m-%d-%H:%M")
listensocket = socket.socket()
listenPort = 9999
numberOfConnections=1
thisIp = socket.gethostname()
listensocket.bind(('', listenPort))
listensocket.listen(numberOfConnections)
print("Started Listening")
(clientsocket, address) = listensocket.accept()
print("Connected")
fname = "/home/pi/Desktop/Images/"+date_string+".PNG"
f = open(fname, 'wb')
datain = 1
while datain:
datain = clientsocket.recv(100000000)
print(datain)
bytearray(f.write(datain))
f.close()
listensocket.close()
【问题讨论】:
-
您的 python 代码包含一些无意义的语句,例如
datain = clientsocket.recv(100000000)和bytearray(f.write(datain))。但最重要的问题是你的 python 协议没有计算你的 Java 协议。您的 Java 代码首先将要跟随的数据长度写为 64 位大端整数。您的 python 不会尝试读取这个 64 位整数,而是将这 8 个字节视为图像文件的一部分。 -
那将来自 dos.writeLong。但是如何在 python 中将二进制文件写为 Long 类型?
-
@PresidentJamesK.Polk 提出了很好的观点。在您的 Python 服务器中,如果您只是跳过前 8 个字节,您最终可能会得到一个可行的图像文件。更好的是,读取这 8 个字节并将它们解释为整数值(注意字节顺序)。然后,您可以通过添加 socket.MSG_WAITALL 以显式长度调用 recv() 在这种情况下,您不需要循环
-
@JohnJones 看看 struct 模块中可用的打包和解包功能。您还可以查看我给出的答案 here
-
到目前为止的 cmets 确实让我走上了正轨。我确定它与发送到服务器的 Long 类型图像有关。但我不知道如何阅读它。此外,如果我可以添加灵活的策略来读取不同的图像尺寸会有所帮助,而不仅仅是对我。我是一个尝试学习的初学者,有没有关于如何达到预期结果的例子?这对我来说并不容易
标签: python java android-studio sockets tcp