Большая передача файлов с сокетами - PullRequest
4 голосов
/ 25 февраля 2011

Когда я передаю большой файл с помощью сокет-программирования, полученный файл является неполным, то есть это mp3-файл, который, когда я играю, звучит странно. Код:

Серверная часть:

File myFile = new File("abc.mp3");
{
    Socket sock = servsock.accept();
    int packetsize=1024;
    double nosofpackets=Math.ceil(((int) myFile.length())/packetsize);
    BufferedInputStream bis = new BufferedInputStream(new FileInputStream(myFile));
    for(double i=0;i<nosofpackets+1;i++) {
        byte[] mybytearray = new byte[packetsize];
        bis.read(mybytearray, 0, mybytearray.length);
        System.out.println("Packet:"+(i+1));
        OutputStream os = sock.getOutputStream();
        os.write(mybytearray, 0,mybytearray.length);
        os.flush();
    }
}

Клиентская сторона:

int packetsize=1024;
FileOutputStream fos = new FileOutputStream("zz.mp3");
BufferedOutputStream bos = new BufferedOutputStream(fos);
double nosofpackets=Math.ceil(((int) (new File("abc.mp3")).length())/packetsize);
for(double i=0;i<nosofpackets+1;i++)
{
    InputStream is = sock.getInputStream();
    byte[] mybytearray = new byte[packetsize];
    int bytesRead = is.read(mybytearray, 0,mybytearray.length );
    System.out.println("Packet:"+(i+1));
    bos.write(mybytearray, 0,mybytearray.length);
}
sock.close();
bos.close();

На стороне клиента я использовал new File("abc.mp3")).length просто для простоты (я мог бы отправить длину файла со стороны сервера).

Этот код отлично работает, если клиент и сервер - одна и та же машина, но файл искажается, если они находятся на разных машинах.

Ответы [ 4 ]

18 голосов
/ 25 февраля 2011

Канонический способ скопировать поток в Java:

int count;
byte[] buffer = new byte[8192];
while ((count = in.read(buffer)) > 0)
{
  out.write(buffer, 0, count);
}

Работает с любым размером буфера больше нуля. Искушения связать размер буфера с входным размером следует усиленно избегать.

8 голосов
/ 25 февраля 2011

Я думаю, что проблема в том, что вы игнорируете значения, возвращаемые различными вызовами read, и предполагаете, что они полностью заполняют буфер.Это проблематично:

  • При чтении из файла чтение last , вероятно, не заполнит буфер.

  • При чтении из сокета, любое чтение может вернуться до заполнения буфера.

Чистый результат, который ваши записи будут помещать в поток мусора (на сервереконец) и в файл назначения (на стороне клиента).

Кроме того, бессмысленно делить файл на куски в зависимости от размера файла.Просто читайте, пока не дойдете до конца файла.

6 голосов
/ 19 декабря 2012

Не изобретайте велосипед, используйте IOUtils.copy().

0 голосов
/ 25 февраля 2011

Не используйте пакеты.Попробуйте использовать ByteArrayOutputStream вместо использования статического байтового массива.продолжайте читать из входного потока, пока не достигнете EOF.n записать все это в ByteArrayOutputStream.


InputStream is = sock.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int byteToBeRead = -1;
while((byteToBeRead = is.read())!=-1){
baos.write(byteToBeRead);
}
byte[] mybytearray = baos.toByteArray();
bos.write(mybytearray, 0,mybytearray.length);

Надеюсь, это поможет.

...