сервер отправляет файл клиентам java

#java

#java

Вопрос:

У меня есть сервер и несколько клиентов, и я пытаюсь заставить серверный поток отправлять файл всем подключенным клиентам одновременно.Странно то, что иногда файлы записываются правильно, а иногда ноутбук издает шум, и файлы записываются в консоль, но файлы не создаются.Я не делаю никаких изменений в коде между испытаниями.Кто-нибудь может мне помочь в этом? Заранее спасибо.Вот код отправляющего серверного потока

 try
{   
    out.println("AcceptFile,");
    FileInputStream fis = new FileInputStream(fn);
    byte[] buffer = new byte[fis.available()];
    fis.read(buffer);
    ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream()) ;
    oos.writeObject(buffer);
    oos.flush();
}
catch(Exception c)
{
    System.err.println("exc"   c);
}
  

Вот клиентский поток, получающий

 try
{
    ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
                    byte[] buffer = (byte[])ois.readObject();
                    String pic="copy" studId ".pdf";
                    System.out.println(pic);
                    FileOutputStream fos = new FileOutputStream(pic);
                    fos.write(buffer);  
                    fos.flush();
                    fos.close();    
}
catch(Exception e)
{
    System.out.println("Exception writing");
}
  

Ответ №1:

Это повторяющаяся проблема, которую я вижу снова и снова. У вас нет гарантий, что базовый сокет не будет очищен, когда вы этого не хотите. Если это произойдет, то клиент может получить частичный объект, и ObjectInputStream выдаст исключение.

Способ справиться с этим — заставить сервер записать объект в промежуточный байт [] через ByteArrayOutputStream. Затем вы отправляете простой заголовок, описывающий длину последующих байтов, за которым следует содержимое байта[] (сбрасывается после каждой записи). На стороне клиента вы делаете обратное: считываете простой заголовок, чтобы знать, сколько байтов ожидать, затем считываете в byte[] через ByteArrayInputStream , а оттуда вы можете считывать в ObjectInputStream. Конечно, поскольку вы все равно просто записываете в файл, вы могли бы пропустить ObjectInputStream на стороне клиента и просто напрямую записать byte[] в файл.

 import java.io.*;

public class junk extends ClassLoader {


  public static void main(String[] args) throws Exception {
    new junk();
  }

  public void marshal(OutputStream socketOutputStream, Object obj) 
    throws Exception 
  {

    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream(bos);

    oos.writeObject(obj);

    byte[] bytes = bos.toByteArray();

    DataOutputStream dos = new DataOutputStream(socketOutputStream);

    // header
    dos.writeInt(bytes.length);
    dos.flush();

    dos.write(bytes);
    dos.flush();
  }

  public Object unmarshal(InputStream socketInputStream) throws Exception {

    DataInputStream dis = new DataInputStream(socketInputStream);

    int numToRead = dis.readInt();

    byte[] bytes = new byte[numToRead];

    dis.readFully(bytes);

    ByteArrayInputStream bis = new ByteArrayInputStream(bytes);

    ObjectInputStream ois = new ObjectInputStream(bis);

    return ois.readObject();

  }

}
  

Комментарии:

1. И на стороне чтения клиентом вам также необходимо обслуживать разделенные пакеты, поэтому вам нужно продолжать чтение, пока вы не прочитаете numToRead байт.

2. @user2726092 Я пробовал это, но с небольшими изменениями, чтобы создать файл, но это не работает. Вот поток ввода данных на стороне клиента dis = новый поток ввода данных (socket.getInputStream()); int numToRead = dis.readInt();byte[] bytes = новый байт[numToRead];dis.readFully(байты);ByteArrayInputStream bis = новый поток ввода данных (байты);ObjectInputStream ois = новый поток ввода объекта (bis);ois.readObject(); Строка pic =»копировать» studId «.pdf»;System.out.println(рис.);FileOutputStream fos = новый FileOutputStream (рис.);fos.write (байты); fos. flush();fos.close();`

3. И на стороне сервера out.println("AcceptFile,"); ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject((Object)fn); byte[] bytes = bos.toByteArray(); DataOutputStream dos = new DataOutputStream(socket.getOutputStream()); // header dos.writeInt(bytes.length); dos.flush(); dos.write(bytes); dos.flush();