Nie można wykryć odłączonego kabla ethernetowego tylko za pomocą wywołania funkcji write(). Dzieje się tak z powodu retransmisji tcp działającej na stosie tcp bez twojej świadomości. Oto rozwiązania.
Nawet jeśli już ustawiłeś opcję keepalive na swoje gniazdo aplikacji, nie możesz na czas wykryć stanu martwego połączenia gniazda, na wypadek, gdyby aplikacja zapisywała na gnieździe. Dzieje się tak z powodu retransmisji tcp przez stos tcp jądra. tcp_retries1 i tcp_retries2 są parametrami jądra do konfiguracji limitu czasu retransmisji tcp. Trudno jest przewidzieć dokładny czas opóźnienia retransmisji, ponieważ jest on obliczany przez mechanizm RTT. Możesz zobaczyć to obliczenie w rfc793. (3.7. Komunikacja komputerowa)
https://www.rfc-editor.org/rfc/rfc793.txt
Każdy platformy mają konfiguracje kernela dla TCP retransmisji.
Linux : tcp_retries1, tcp_retries2 : (exist in /proc/sys/net/ipv4)
http://linux.die.net/man/7/tcp
HPUX : tcp_ip_notify_interval, tcp_ip_abort_interval
http://www.hpuxtips.es/?q=node/53
AIX : rto_low, rto_high, rto_length, rto_limit
http://www-903.ibm.com/kr/event/download/200804_324_swma/socket.pdf
należy ustawić niższą wartość dla tcp_retries2 (domyślnie 15), jeśli chcesz, aby wcześnie wykryć martwe połączenie, ale to nie tak dokładny czas jak ja powiedziany. Ponadto obecnie nie można ustawić tych wartości tylko dla pojedynczego gniazda. Są to globalne parametry jądra. Była próba zastosowania opcji gniazda retransmisji tcp dla pojedynczego gniazda (http://patchwork.ozlabs.org/patch/55236/), ale nie sądzę, że została zastosowana w głównej linii jądra. Nie mogę znaleźć tych opcji w plikach nagłówkowych systemu.
Dla odniesienia, możesz monitorować twój keepalive gniazdo przez 'netstat --timers' jak poniżej. https://stackoverflow.com/questions/34914278
netstat -c --timer | grep "192.0.0.1:43245 192.0.68.1:49742"
tcp 0 0 192.0.0.1:43245 192.0.68.1:49742 ESTABLISHED keepalive (1.92/0/0)
tcp 0 0 192.0.0.1:43245 192.0.68.1:49742 ESTABLISHED keepalive (0.71/0/0)
tcp 0 0 192.0.0.1:43245 192.0.68.1:49742 ESTABLISHED keepalive (9.46/0/1)
tcp 0 0 192.0.0.1:43245 192.0.68.1:49742 ESTABLISHED keepalive (8.30/0/1)
tcp 0 0 192.0.0.1:43245 192.0.68.1:49742 ESTABLISHED keepalive (7.14/0/1)
tcp 0 0 192.0.0.1:43245 192.0.68.1:49742 ESTABLISHED keepalive (5.98/0/1)
tcp 0 0 192.0.0.1:43245 192.0.68.1:49742 ESTABLISHED keepalive (4.82/0/1)
Ponadto, gdy keepalive ocurrs limitu czasu, można spotkać różne wydarzenia powrotne w zależności od platformy używasz, więc nie musi decydować stan martwego połączenia tylko przez wydarzenia w obie strony. Na przykład HP zwraca zdarzenie POLLERR, a system AIX zwraca tylko zdarzenie POLLIN po przekroczeniu limitu czasu keepalive. W tym czasie wystąpi błąd ETIMEDOUT w wywołaniu recv().
W najnowszej wersji jądra (od wersji 2.6.37) można użyć opcji TCP_USER_TIMEOUT. Ta opcja może być używana dla pojedynczego gniazda.
Wreszcie można użyć funkcji odczytu z flagą MSG_PEEK, która pozwala sprawdzić, czy gniazdo jest w porządku. (MSG_PEEK po prostu sprawdza, czy dane dotarły do bufora stosu jądra i nigdy nie kopiuje danych do bufora użytkownika.) Możesz więc użyć tej flagi tylko do sprawdzenia, czy gniazdo jest w porządku bez żadnych skutków ubocznych.
Pytanie dotyczy odłączenia kabla Ethernet. – EJP