обзор
В c ++ (gcc-c ++ 6.3.1) на Fedora 24 x86_64 с использованием стандартного API сокетов я делаю базовый FTP-клиент, основанный на нескольких избранных компонентах: RFC-959. Я иногда сталкиваюсь с проблемой, что при получении или отправке данных на сервер, соединение для передачи данных сбрасывается. У меня нет проблем с закрытием сокета и продолжением выполнения в случае чтения данных, но моя программа отключается довольно серьезно при выполнении записи (например, при put
/STOR
).
Пока что в этой программе много кода, поэтому я включу наиболее важные части в свой ответ и попытаюсь абстрагироваться от остальных. Если нужны дополнительные сегменты кода, я добавлю их по запросу.
Подробный процесс
Предположим, что управляющее соединение уже функционирует и пользователь аутентифицирован.
PASV
).STOR
)errno
значение подтверждено равным ECONNRESET
наблюдения
При попытке закрыть соединение в шаге 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 () на самом деле не закрывают сокет, и как я могу заставить его не возвращаться, пока это не удастся сделать?
Задача ещё не решена.
Других решений пока нет …