读取从套接字接收到的图像时出错
Error while reading image received from socket
我有一个 android 应用程序,它通过套接字将图像从画廊发送到 Python 服务器,使用 DataOutputStream 写入客户端应用程序中的套接字。图像从外部存储目录加载并在发送前进行缓冲。图像由服务器接收并写入磁盘内存。当我尝试打开图像时,它给我:“读取图像文件时出现致命错误。不是 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()
这个答案可能不够可靠,但确实展示了一种有效地将文件从 Java 应用程序传输到 Python 服务器的机制。出于演示目的,某些路径是硬编码的。另请注意,如果正在传输的文件非常大,这可能不合适,因为在写入目标文件之前,整个文件内容将保存在服务器端的内存中。显然,这可以用更详细的代码来解释。
这是 Java 客户端:
package com.aprk;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;
public class GetImage {
public static void main(String[] args) {
try {
Socket s = new Socket("localhost", 7070);
File image = new File("/Volumes/G-DRIVE Thunderbolt 3/Pictures/rgb_colour_wheel.png");
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(image));
BufferedOutputStream bos = new BufferedOutputStream(s.getOutputStream());
bos.write(nio(image.length()));
byte[] buff = new byte[4096];
int n;
while ((n = bis.read(buff, 0, buff.length)) > 0) {
bos.write(buff, 0, n);
}
bos.flush();
} catch (IOException ex) {
Logger.getLogger(GetImage.class.getName()).log(Level.SEVERE, null, ex);
}
}
private static byte[] nio(long n) {
byte[] v = new byte[8];
int shift = 56;
for (int i = 0; i < 8; i++) {
v[i] = (byte)(n>>shift);
shift -= 8;
}
return v;
}
}
这是 Python 服务器:
import socket
from struct import unpack
HOST = '0.0.0.0'
PORT = 7070
def main():
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT))
s.listen()
conn, _ = s.accept()
with conn:
p = conn.recv(8, socket.MSG_WAITALL)
n = unpack('!Q', p)[0]
with open('/tmp/image.png', 'wb') as image:
while n > 0:
data = conn.recv(n)
image.write(data)
n -= len(data)
if __name__ == '__main__':
main()
我有一个 android 应用程序,它通过套接字将图像从画廊发送到 Python 服务器,使用 DataOutputStream 写入客户端应用程序中的套接字。图像从外部存储目录加载并在发送前进行缓冲。图像由服务器接收并写入磁盘内存。当我尝试打开图像时,它给我:“读取图像文件时出现致命错误。不是 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()
这个答案可能不够可靠,但确实展示了一种有效地将文件从 Java 应用程序传输到 Python 服务器的机制。出于演示目的,某些路径是硬编码的。另请注意,如果正在传输的文件非常大,这可能不合适,因为在写入目标文件之前,整个文件内容将保存在服务器端的内存中。显然,这可以用更详细的代码来解释。
这是 Java 客户端:
package com.aprk;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;
public class GetImage {
public static void main(String[] args) {
try {
Socket s = new Socket("localhost", 7070);
File image = new File("/Volumes/G-DRIVE Thunderbolt 3/Pictures/rgb_colour_wheel.png");
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(image));
BufferedOutputStream bos = new BufferedOutputStream(s.getOutputStream());
bos.write(nio(image.length()));
byte[] buff = new byte[4096];
int n;
while ((n = bis.read(buff, 0, buff.length)) > 0) {
bos.write(buff, 0, n);
}
bos.flush();
} catch (IOException ex) {
Logger.getLogger(GetImage.class.getName()).log(Level.SEVERE, null, ex);
}
}
private static byte[] nio(long n) {
byte[] v = new byte[8];
int shift = 56;
for (int i = 0; i < 8; i++) {
v[i] = (byte)(n>>shift);
shift -= 8;
}
return v;
}
}
这是 Python 服务器:
import socket
from struct import unpack
HOST = '0.0.0.0'
PORT = 7070
def main():
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT))
s.listen()
conn, _ = s.accept()
with conn:
p = conn.recv(8, socket.MSG_WAITALL)
n = unpack('!Q', p)[0]
with open('/tmp/image.png', 'wb') as image:
while n > 0:
data = conn.recv(n)
image.write(data)
n -= len(data)
if __name__ == '__main__':
main()