PrintWriter против DataOutputStream, странное поведение - PullRequest
0 голосов
/ 13 июля 2011

Я создаю модель сервер / клиент для отправки файла изображения с сервера на клиент. Включен только ОДИН сокет (все данные передаются через него).
Сервер сначала отправляет размер файла изображения, затем отправляет данные файла в байтах через BufferedOutputStream. Клиент сначала получает размер файла (размер), создает байт [размер] imageBytes, затем записывает полученные данные файла в imageBytes через BufferedInputStream.

Кажется, прямо вперед. Проблема возникает, когда я отправляю размер файла разными способами.

Способ 1: использование DataOutputStream и DataInputStream для отправки и получения размера файла как int.

Способ 2: использование PrintWriter для печати (размер файла), затем очистка; использование BufferedReader для readLine ().

Способ 1 работает нормально. Но способ 2 отправляет файл изображения неправильно.

Интересно, так ли это, потому что BufferedReader все еще сохраняет свой буфер после чтения, и этот буфер впоследствии читается BuffereInputStream.

Вот коды:

Сервер:

    package test;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class TestServer {

    public static void main(String[] args){
        try {
            ServerSocket serverSocket = new ServerSocket(9090);
            Socket ss = serverSocket.accept();
            System.out.println("Client connected!");

            File file = new File("ServerFiles/Songs/Covers/album1.jpg"); //Change this path to your own path
            BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
            byte[] imageBytes = new byte[(int) file.length()];
            bis.read(imageBytes);
            bis.close();

            //Way 1-------------------------------------------------------------
            DataOutputStream dos = new DataOutputStream(ss.getOutputStream());
            dos.writeInt((int) file.length());
            System.out.println("dos wrote "+file.length());
            //End Way 1---------------------------------------------------------

            //Way 2-------------------------------------------------------------
//          PrintWriter pw = new PrintWriter(ss.getOutputStream());
//          pw.println(file.length());
//          pw.flush();
//          System.out.println("pw flushed!");
            //End Way 2---------------------------------------------------------

            BufferedOutputStream bos = new BufferedOutputStream(ss.getOutputStream());
            bos.write(imageBytes);
            bos.flush();
            System.out.println("bos flushed!");
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

Клиент:

    package test;

import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class TestClient extends JFrame{
    Socket cs;
    ImageIcon imageIcon;

    public static void main(String[] args){
        try {
            Socket socket = new Socket(InetAddress.getLocalHost(), 9090);
            new TestClient(socket);
        } catch (UnknownHostException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

    public TestClient(Socket cs) throws IOException{
        this.cs = cs;
        init();
    }

    private void init() throws IOException{
        imageIcon = getImageIcon();
        JLabel jl = new JLabel(imageIcon);
        JPanel content = (JPanel) this.getContentPane();
        content.add(jl);

        this.setSize(600,400);
        this.setVisible(true);
    }

    private ImageIcon getImageIcon() throws IOException{

        //Way 1-------------------------------------------------------------
        DataInputStream dis = new DataInputStream(cs.getInputStream());
        int size = dis.readInt();
        System.out.println("size="+size);
        //End Way 1---------------------------------------------------------

        //Way 2-------------------------------------------------------------
//      BufferedReader br = new BufferedReader(new InputStreamReader(cs.getInputStream()));
//      int size = Integer.parseInt(br.readLine());
//      System.out.println("size="+size); //Print size
        //End Way 2---------------------------------------------------------

        BufferedInputStream bis = new BufferedInputStream(cs.getInputStream());
        System.out.println("bis.available()="+bis.available()); //Print bis.available()
        byte[] imageBytes = new byte[size];
        bis.read(imageBytes);
        return new ImageIcon(imageBytes);
    }
}

Выходы:

Путь 1:

Сервер:

Client connected!
dos wrote 23215
bos flushed!

Клиент:

size=23215
bis.available()=23215

Путь 2:

Сервер:

Client connected!
pw flushed!
bos flushed!

Клиент:

size=23215
bis.available()=6837

Ответы [ 2 ]

0 голосов
/ 13 июля 2011

Нет контракта на входные потоки, который говорит, что вы получите все данные за одно чтение. Вы должны продолжать циклически выполнять функцию available (), пока она не вернет отрицательное число. Для этого измените код, а затем снова сравните два сценария.

0 голосов
/ 13 июля 2011

Я бы сказал, что разница в том, что DataOutputStream записывает целое число в двоичном формате, то есть оно разбивает целое число на 4 байта и записывает их, тогда как PrintWriter делает String.valueOf(paramInt) и, таким образом, отправляет байты строка "23215" клиенту.

Поскольку вы уже отправляете двоичные данные (изображение), почему бы вам не придерживаться пути 1? Обычно вам не нужно, чтобы заголовок был удобочитаемым.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...