Проблема при отправке файла с сервера UDP - PullRequest
0 голосов
/ 09 марта 2011

Я пишу небольшой UDP-сервер на Java. Когда сервер получает команду ('GET_VIDEO'), он читает файл ('video.raw') и затем отправляет его клиенту. Моя проблема в том, что количество байтов, отправленных с сервера, не равно количеству байтов, полученных клиентом, и мой тест не прошел. Вот код сервера:

public class ServerMock {

public static void main(String[] args) throws Exception {

    byte[] buff = new byte[64];
    DatagramPacket packet = new DatagramPacket(buff, buff.length);
    DatagramSocket socket = new DatagramSocket(8080);

    System.out.println("Server started at 8080 ...");

    while (true) {
        socket.receive(packet);
        new ServerMock.ThreadVideo(socket, packet).run();

    }
}

public static class ThreadVideo implements Runnable {

    private DatagramPacket packet;
    private DatagramSocket socket;

    public ThreadVideo(DatagramSocket socket, DatagramPacket packet) {
        this.packet = packet;
        this.socket = socket;
    }

    public void run() {
        String cmd = new String(packet.getData(), 0, packet.getLength());
        if (cmd.equals("GET_VIDEO")) {
            try {
                read_and_send_video(this.packet.getAddress());
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            System.out.println("S:Exiting ....");
            System.exit(0);
        }
    }


    private void read_and_send_video(InetAddress address)
            throws IOException {

        File file = new File("./video/video.raw");
        FileInputStream fis = new FileInputStream(file);
        DatagramPacket pack;

        int size = 0;
        byte[] buffer = new byte[64000];
        ByteBuffer bb = ByteBuffer.allocate(4);
        bb.order(ByteOrder.BIG_ENDIAN);

        while (true) {
            size = fis.read(buffer);
            System.out.println("Size = " + size);

            // Envoi du contenu du fichier
            pack = new DatagramPacket(buffer, buffer.length, address,
                    packet.getPort());
            socket.send(pack);
            if (size == -1) {
                break;
            }
        }

        String cmd = "END_VIDEO";
        pack = new DatagramPacket(cmd.getBytes(), cmd.getBytes().length,
                address, packet.getPort());
        socket.send(pack);

    }

}

}

Вот мой код клиента:

public void client(int timeout, String message)
        throws SocketTimeoutException, SocketException {

    try {

        File file = new File("./video/tmp.raw");
        FileOutputStream fos = new FileOutputStream(file);
        File filein = new File("./video/video.raw");

        InetAddress address = InetAddress.getByName(host);
        byte[] data = message.getBytes();
        byte[] buffer = new byte[64000];

        DatagramSocket socket = new DatagramSocket();
        socket.setSoTimeout(timeout);

        DatagramPacket packet = new DatagramPacket(data, data.length,
                address, port);
        socket.send(packet);

        DatagramPacket rpacket = new DatagramPacket(buffer, buffer.length);

        while (true) {
            socket.receive(rpacket);
            if (rpacket.getLength() <= 9) {
                String cmd = new String(rpacket.getData(), 0,
                        rpacket.getLength());
                if (cmd.equals("END_VIDEO")) {
                    System.out.println("C:Fin de transmission");
                    break;
                }
            }
            fos.write(rpacket.getData());
        }

        System.out.println("video.raw ->" + filein.length());
        System.out.println("tmp.raw -> " + file.length());
        Assert.assertTrue(file.length() == filein.length());

    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (UnknownHostException e) {

        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }

}

Любой может помочь мне с этой проблемой. Некоторые друзья советуют мне использовать класс ByteBuffer, ByteOrder, но я не знаю, как их использовать, так как я не знаю, сколько байтов действительно читается, когда сервер читает файл. Какой лучший способ добиться этого

Спасибо

Ответы [ 2 ]

4 голосов
/ 09 марта 2011

UDP ненадежен, нет никакой гарантии, что вы получите все отправленные пакеты UDP или что вы получите их в порядке их отправки.Вам нужно будет пометить каждый пакет порядковым номером, вам нужно будет переупорядочить их на клиенте, вам нужно будет сообщить серверу, когда нужно замедлить работу (или реализовать механизм подтверждения), вам понадобится возможность запросить повторную передачу..

Короче говоря, если клиент не удовлетворен потерянными и неупорядоченными пакетами (как большинство потоковых клиентов), вам потребуется переопределить TCP через UDP или просто использовать TCP.

1 голос
/ 18 мая 2011

Я искал пример отправки файла с сервера udp и нашел ваш вопрос.Вы должны изменить следующие строки:

На сервере:

    int size = 0;
    byte[] buffer = new byte[(int) file.length()];
    ByteBuffer bb = ByteBuffer.allocate(4);
    bb.order(ByteOrder.BIG_ENDIAN);

, а также вы должны переместить "socket.send (packet)":

while (true) {
size = fis.read(buffer);
System.out.println("Size = " + size);

// Envoi du contenu du fichier
pack = new DatagramPacket(buffer, buffer.length, address, packet.getPort());

if (size == -1) {
   break;
}

    socket.send(pack);
 }

В клиенте измените fos.write(rpacket.getData()); с помощью fos.write(rpacket.getData(), 0, rpacket.getLength());

...