2011-06-07 3 views
1

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

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

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

ответ

0

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

3

Вы получаете ошибку до что, прямо на 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(&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 *)&remote, sizeof remote); 
    if (r < 0) { 
      perror("connect"); 
    } 
    return 0; 
} 

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

  • на Linux: connect: Operation now in progress
  • на FreeBSD : connect: Connection refused

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

+0

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

+0

Yup, EINPROGRESS. – Plumenator

+0

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

Смежные вопросы