简体   繁体   中英

Issues sending jpg-image over java socket using datainput/-outputstream

I wish to send a JPG-image from a client to a server over a TCP socket connection. I convert the file to a byte array in the client then send it to the server after having sent the array length. The server reads the data one byte at a time from the socketinputstream to a new bytearray which is then written to a jpg-file. The data however is corrupted and this image cannot be viewed. Below is core java code for client and server.

Client:

Socket s = new Socket("localhost", 666);
DataOutputStream dos = new DataOutputStream(s.getOutputStream());
String imgPath = "C:/Users/huehuehue/Documents/Uni/D0036D/prick1.JPG";
File file = new File(imgPath);
byte[] b = new byte[(int) file.length()];
FileInputStream fis = new FileInputStream(file);
fis.read(b);
fis.close();
dos.writeInt((int) file.length());
dos.flush();
dos.write(b, 0, b.length);
dos.flush();

Server:

ServerSocket serverSocket = new ServerSocket(666);
Socket connect = serverSocket.accept();
DataInputStream dis = new DataInputStream(connect.getInputStream());
File file = new File("C:/Users/huehuehue/Documents/Uni/D0036D/PLAYERprick.JPG");
FileOutputStream fos = new FileOutputStream(file);
int arrlen = dis.readInt();
byte[] b = new byte[arrlen];
int i = 0;
for(i = 0; i < arrlen; i++) {
    b[i] = dis.readByte();
    i++;
}
fos.write(b, 0 , b.length);

I can't see why this wouldn't work and any help or suggestions is greatly appreciated.

int arrlen = dis.readInt();
byte[] b = new byte[arrlen];
int i = 0;
for(i = 0; i < arrlen; i++) {
    b[i] = dis.readByte();
    i++;
}

You're incrementing i twice so you're ignoring half the input, and writing what you don't ignore into the wrong slots. Fortunately there is an easier way, which is also much more efficient:

int arrlen = dis.readInt();
byte[] b = new byte[arrlen];
dis.readFully(b);

NB fis.read(b); isn't valid. You can't assume it fills the buffer. You should use DataInputStream.readFully() here too.

You need to match both ends of the socket and your client doesn't fill your byte[] fully; instead your client could send each byte as it reads it. And, since Java provides BufferedInputStream you don't have to manually use and tweak a byte[] buffer directly. Instead you could do something like,

Socket s = new Socket("localhost", 666);
String imgPath = "C:/Users/huehuehue/Documents/Uni/D0036D/prick1.JPG";
File file = new File(imgPath);
try (InputStream is = new BufferedInputStream(new FileInputStream(file));
        DataOutputStream dos = new DataOutputStream(s.getOutputStream());) {
    dos.writeLong(file.length()); // <-- remember to read a long on server.
    int val;
    while ((val = is.read()) != -1) {
        dos.write(val);
    }
    dos.flush();
}

Also, your server could use the similar BufferedOutputStream to get the benefit of a buffer like

ServerSocket serverSocket = new ServerSocket(666);
File file = new File("C:/Users/huehuehue/Documents/Uni/D0036D/PLAYERprick.JPG");
try (Socket s = serverSocket.accept();
        DataInputStream dis = new DataInputStream(
                s.getInputStream());
        OutputStream fos = new BufferedOutputStream(
                new FileOutputStream(file));) {
    long arrlen = dis.readLong();
    for (long i = 0; i < arrlen; i++) {
        fos.write(dis.read());
    }
    fos.flush();
}

without having to manually manage it. Notice the above use BufferedInputStream and BufferedOutputStream to manage the buffering as an optimization. You could remove them and read and write directly from the File streams.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM