Неблокирующее подключение к адресу обратной связи (127.0.0.1 или localhost)

#ios #macos #freebsd #ios-simulator

#iOS #macos #freebsd #ios-симулятор

Вопрос:

Когда я выполняю неблокирующее подключение к адресу обратной связи из симулятора iOS (который, вероятно, использует тот же стек TCP, что и Mac и FreeBSD), я вижу, что подключение всегда выполняется успешно, даже когда серверный процесс не запущен.

Я обнаружил, что подключение прошло успешно с помощью select () с нулевым таймаутом. Итак, пока select () возвращает 0, я предполагаю, что соединение выполняется, если оно возвращает -1, я выдаю ошибку, а если оно возвращает 1, сокет готов к чтению (поскольку сервер, должно быть, ответил), и я начинаю чтение после сообщения о том, что подключение прошло успешно.

Это хорошо работает для всех адресов, кроме обратного. При обратной связи select() всегда возвращает 1, даже если сервер не запущен. Итак, я начинаю чтение, которое завершается неудачей, и я его обрабатываю. Но я должен был обнаружить это с помощью select ()!

Ответ №1:

Вы получаете ошибку, предшествующую этому, сразу после connect() . Прежде чем продолжить select() , убедитесь, что это errno есть EINPROGRESS , а не что-то еще. В * BSD соединения с неподслушивающим портом при localhost ошибке выводятся (или могут выводиться с ошибкой) немедленно.

Я только что провел очень простой тест, подобный этому (заголовки пропущены):

 int
main(void)
{
    int fd;
    int r;
    struct sockaddr_in remote;
    struct hostent *he;

    he = gethostbyname("localhost");
    if (he == NULL)
            return -1;

    memcpy(amp;remote.sin_addr, he->h_addr, sizeof(remote.sin_addr));
    remote.sin_port = htons(9671);
    remote.sin_family = AF_INET;

    fd = socket(PF_INET, SOCK_STREAM, 0);
    fcntl(fd, F_SETFL, O_NONBLOCK);

    r = connect(fd, (struct sockaddr *)amp;remote, sizeof remote);
    if (r < 0) {
            perror("connect");
    }
    return 0;
}
  

Поскольку на порту ничего не прослушивается 9671 , я получил:

  • в Linux: connect: Operation now in progress
  • во FreeBSD: connect: Connection refused

Конечно, всегда полезно проверять коды ошибок всех системных вызовов (чего приведенный выше пример для простоты не делает — в конце концов, это всего лишь иллюстрация).

Комментарии:

1. На самом деле я получаю EINPROGRESS от connect (). Я проверю еще раз и дам вам знать.

2. Прошу прощения за предположение, что вы не проверили результат connect . Кстати, вы выбираете для чтения или для записи? По крайней мере, на connect(2) странице руководства FreeBSD, похоже, указано, что следует выбрать для записи.

3. Да, я действительно выбрал для записи. Спасибо за ваши усилия!

Ответ №2:

Проблема заключалась в том, что я полагался на select (), чтобы сообщить мне, было ли соединение успешным. Select сообщает вам только о том, изменилось ли что-либо в этом fd. На самом деле я должен был снова вызвать connect () в сокете и убедиться, что в случае сбоя ошибка либо EINPROGRESS, либо ECONN, либо EALREADY. За исключением ECONN, все остальные значения означают, что мы должны повторить попытку; ECONN означает, что он уже подключен. Любое другое значение errno означает, что нам не удалось подключиться.