FTP-клиент: сброс соединения, не удается закрыть соединение, пока приложение не закроется

обзор

В c ++ (gcc-c ++ 6.3.1) на Fedora 24 x86_64 с использованием стандартного API сокетов я делаю базовый FTP-клиент, основанный на нескольких избранных компонентах: RFC-959. Я иногда сталкиваюсь с проблемой, что при получении или отправке данных на сервер, соединение для передачи данных сбрасывается. У меня нет проблем с закрытием сокета и продолжением выполнения в случае чтения данных, но моя программа отключается довольно серьезно при выполнении записи (например, при put/STOR).

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

Подробный процесс

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

  1. Я запрашиваю пассивный режим на сервер (PASV).
  2. Я получаю пассивный ответ (227).
  3. Я открываю соединение для передачи данных, учитывая IP-адрес ответа и номер порта.
  4. Я запрашиваю запрос магазина на сервер (STOR)
  5. Я получил одобрение магазина (150)
  6. Я вызываю send () в первый раз, отправляя некоторые данные, но возвращается -1.
  7. errno значение подтверждено равным ECONNRESET
  8. Я пытаюсь закрыть сокет
  9. Я прочитал контрольное соединение для подтверждения от сервера (226)

наблюдения

При попытке закрыть соединение в шаге 8 выше, я попробовал несколько разных вещей.

shutdown(fileDescriptor, [any flag])
возвращает -1, ENOTCONN/ 107, конечная точка транспорта не подключена.

close(fileDescriptor) возвращает 0 за успех (иногда я видел ECONNRESET здесь тоже).

Это поведение не меняется при настройке SO_LINGER немедленно закрыть. На самом деле, Самое интересное часть в том, что после того, как сервер отправляет Rst пакет, мой клиент никогда не отправляет свой Rst или же Fin пока я не закончу программу.

Включение TCP_NODELAY для отключения алгоритма Nagle ничего не меняет.

Packet Watch: стандартный FTP-клиент

Это наблюдение за пакетами, передаваемыми по стандартному FTP-клиенту, который поставляется с большинством операционных систем Unix.

Packet         Direction  Purpose
ftp: PASV      -->        Client prompt for passive mode
ftp: 227       <--        Server approve passive mode
tcp: Syn     -->        Client initiate handshake for data connection
tcp: Syn+Ack <--        Server acknowledge handshake
tcp: Ack     -->        Client acknowledge acknowledgement
ftp: STOR      -->        Client prompt to store file
ftp: 150       <--        Server approve of store request
tcp: Rst+Ack <--        Server warns that connection is closed/reset
tcp: Fin+Ack -->        Client closes connection
tcp: Ack     -->        Client acknowledges server
ftp: 226       <--        Server sends response that file upload done

Различия на моем клиенте

Если вы наблюдаете ту же транзакцию от моего клиента, Fin+Ack или же Rst пакеты никогда не отправляются, когда close() или же shutdown() называется.

После того, как это соединение для передачи данных не закрывается, управляющее соединение отказывается отправлять какие-либо дополнительные ответы, что приводит к зависанию всех будущих команд. Но как только я закрываю программу, перезагрузка отправляется на все открытые соединения, и соединения закрываются.

Кто-нибудь знает какие-либо очевидные проблемы, с которыми я могу столкнуться при попытке разорвать соединение для передачи данных? Почему shutdown () или close () на самом деле не закрывают сокет, и как я могу заставить его не возвращаться, пока это не удастся сделать?

0

Решение

Задача ещё не решена.

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]