Почему в iOS не происходит сбой сокета recv при изменении базовой сети?

В iOS, когда у меня есть сокет блокировки с таймаутом, установленным с помощью SO_RCVTIMEO. Когда я изменяю сеть Wi-Fi, к которой подключено устройство, вызовы recv будут соответственно задерживаться, но errno будет сообщаться как EWOULDBLOCK и recv возвращает -1.

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

Если я просто уничтожу сеть в целом, несколько повторных вызовов recv в конечном итоге потерпят неудачу с ETIMEDOUT, после многих EWOULDBLOCK.

Почему это происходит? Разве соединение с сокетом не должно быть разорвано и завершиться с ошибкой с помощью ENETRESET или аналогичной ошибки?

Если у меня нет SO_RCVTIMEO, то при изменении сети WiFi сокет будет блокироваться навсегда. Также нет Буэно.

РЕДАКТИРОВАТЬ: я думаю, что я мог бы просто включить SO_KEEPALIVE на локальном сокете, чтобы определить, когда удаленный сокет перестает отвечать из-за изменения базовой конечной точки сети. Кажется, это тоже не работает.

1 ответ

Решение

Я отправлю свой ответ здесь. Оказывается, что при использовании keepalive его необходимо сначала включить для уровня сокета SOL_SOCKET, а также установить интервал keepalive на уровне TCP (уровень IPPROTO_TCP с TCP_KEEPALIVE), поскольку по умолчанию обычно используется 7200 секунд (2 часа).

int on = 1;
int delay = 120;
setsockopt(socket_handle, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on));
setsockopt(socket_handle, IPPROTO_TCP, TCP_KEEPALIVE, &delay, sizeof(delay));

Я наткнулся на синтаксис по аналогичному посту.

Можно ли активировать поддержку активности TCP на устройствах Apple iOS?

Другие вопросы по тегам