#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 означает, что нам не удалось подключиться.