Использование 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.