Android Java и сокеты - PullRequest
       2

Android Java и сокеты

1 голос
/ 13 ноября 2011

пишу клиент-серверное приложение.Клиент будет работать на Android и сервер на простой Java.Мне нужно обмениваться данными от клиента к серверу, а затем от сервера к клиенту.Моя проблема в том, что когда я отправляю файл с клиента на сервер, сервер зависает при получении данных из сокета.Вот мой код:

клиент отправляет файл:

    Log.i("======", "sendToServer==============");
    OutputStream output = sk.getOutputStream();     

    String pathToOurFile = directory + File.separator + file;

    FileInputStream fileInputStream = new FileInputStream(pathToOurFile);
    byte[] buffer = new byte[sk.getSendBufferSize()];
    int bytesRead = 0;

    while((bytesRead = fileInputStream.read(buffer))>0)
    {
        output.write(buffer,0,bytesRead);
    }

    fileInputStream.close();

сервер получает данные:

    System.out.println("I get data");
    File file=null;

    InputStream input = sk.getInputStream();

    file = new File("C://protocolFIle/" + "temp.xml");
    FileOutputStream out = new FileOutputStream(file);

    byte[] buffer = new byte[sk.getReceiveBufferSize()];

    int bytesReceived = 0;

    while((bytesReceived = input.read(buffer))>0) {
        out.write(buffer,0,bytesReceived);
    }

    return file;

сервер застрял на линии

while((bytesReceived = input.read(buffer))>0) {
        out.write(buffer,0,bytesReceived);
    }

на стороне сервера.Я думаю, что мне нужно как-то сигнализировать на стороне клиента, когда я закончу отправлять данные.Я знаю, что могу написать «output.close ()» на стороне клиента, а затем сервер получает файл и прерывает цикл, но мне нужен этот вывод в будущем.Кто-нибудь знает, как я могу отправить этот файл, который сервер не застрял?Может быть, мне нужно отправить этот файл по-другому.Спасибо за любую помощь.

1 Ответ

2 голосов
/ 13 ноября 2011

Использование close() на стороне клиента на самом деле не очень поможет, поскольку методы API TCP / IP, такие как close(), практически бесполезны в качестве средства сигнализации об окончании сообщения на прикладном уровне.Причина этого заключается в том, что закрытие потока TCP на стороне клиента не приводит к немедленному закрытию всего соединения TCP вплоть до противоположного клиента.Это все, что связано с базовой архитектурой TCP.

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

Очень важная вещь, которую я хотел бы еще раз подчеркнуть в отношении TCP, заключается в том, что сам протокол TCP и, в частности, такие вызовы, как close(), не предоставляют средств для надежной сигнализации начала / остановки сообщения вашего приложения о том, что вы 'повторная отправка через TCP.TCP должен рассматриваться как протокол stream , потому что это именно то, что он есть;следовательно, вы также должны поместить в этот поток какой-то специальный заголовок с полем длины или символами кадрирования, или каким-либо другим средством указания, когда принимающая сторона прочитала достаточно из вызова .read(), чтобы у него было полное сообщение.

Недавно я создал приложение Android, которое общается с серверным приложением C # с помощью сокетов TCP, и, хотя я отправляю только простые и относительно короткие сообщения через поток, я обнаружил, что реализую очень простые кадрирование сообщений и сообщениязаголовок был абсолютно необходим.

Сигнализация длины или конца сообщения должна выполняться на уровне протокола приложения.

Кроме того, сигнализация о том, что TCP-соединение должно быть закрыто на обоих концах, также должна выполняться на уровне протокола приложения.При поиске в StackOverflow вы часто сталкиваетесь со многими людьми, испытывающими проблемы с определением, было ли TCP-соединение «закрыто».Проблема в том, что это по своей сути неправильный путь к вещам;API сокетов TCP на любом языке просто не может надежно сказать вам, что поток был закрыт.

Если вы посмотрите на HTTP, который является примером популярного протокола с использованием сокетов TCP, вы увидите, что этот протокол использует заголовки, которые указывают длину, и флаги, которые указывают, что соединение должно закрываться, и должен лисообщение фрагментировано и тд.

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

Позже вы можете расширить свой заголовок, чтобы он содержал такие вещи, как значение CRC.

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