2009-05-18 13 views
5
s = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0) 
s.connect(Socket.pack_sockaddr_in('port', 'hostname')) 

ssl = OpenSSL::SSL::SSLSocket.new(s, sslcert) 
ssl.connect 

Odtąd chciałbym sprawdzić w wątku, jeśli połączenie SSL oraz gniazdo bazowy jest nadal ESTABLISHED lub gdy poszedł do CLOSE_WAIT po domyślnie 7200 sekund lub nawet gorzej, ale zamknięty bez faktycznie potrzeby .write() do lub .read() z tego.czy możliwe jest sprawdzenie, czy gniazdo ruby ​​znajduje się w stanie ESTABLISHED, czy CLOSE_WAIT, bez faktycznego wysyłania lub odczytywania danych?

Czy to zrobiono z select(), IO.select() lub inną metodą?

BTW: Gniazdo nigdy nie otrzymuje żadnych danych, które po prostu czasami wysyła.

Odpowiedz

9

Odpowiedź brzmi: implementation specific. Będziesz musiał sprawdzić pliki nagłówkowe implementacji tcp w swoim systemie operacyjnym. Oto przykładowy klient dla systemu Linux, który zwraca stan gniazda.

ts = TCPSocket.new('localhost', 5777) 
    ssl = OpenSSL::SSL::SSLSocket.new(ts, OpenSSL::SSL::SSLContext.new) 
    ssl.sync = true 
    ssl.connect 
    # TCP_INFO is 11 
    # note that TCP_INFO isn't defined in the ruby source. 
    # i had to look up the integer value in /usr/include/netinet/tcp.h 
    optval = ts.getsockopt(Socket::SOL_TCP, 11) 
    state = optval.unpack "i" 
    puts "state: #{state}" 

Oto struct tcp_info dla mojego up-to-date Ubuntu Linux

struct tcp_info 
{ 
    u_int8_t  tcpi_state; 
    u_int8_t  tcpi_ca_state; 
    u_int8_t  tcpi_retransmits; 
    u_int8_t  tcpi_probes; 
    u_int8_t  tcpi_backoff; 
    u_int8_t  tcpi_options; 
    u_int8_t  tcpi_snd_wscale : 4, tcpi_rcv_wscale : 4; 

    u_int32_t  tcpi_rto; 
    u_int32_t  tcpi_ato; 
    u_int32_t  tcpi_snd_mss; 
    u_int32_t  tcpi_rcv_mss; 

    u_int32_t  tcpi_unacked; 
    u_int32_t  tcpi_sacked; 
    u_int32_t  tcpi_lost; 
    u_int32_t  tcpi_retrans; 
    u_int32_t  tcpi_fackets; 

    /* Times. */ 
    u_int32_t  tcpi_last_data_sent; 
    u_int32_t  tcpi_last_ack_sent;  /* Not remembered, sorry. */ 
    u_int32_t  tcpi_last_data_recv; 
    u_int32_t  tcpi_last_ack_recv; 

    /* Metrics. */ 
    u_int32_t  tcpi_pmtu; 
    u_int32_t  tcpi_rcv_ssthresh; 
    u_int32_t  tcpi_rtt; 
    u_int32_t  tcpi_rttvar; 
    u_int32_t  tcpi_snd_ssthresh; 
    u_int32_t  tcpi_snd_cwnd; 
    u_int32_t  tcpi_advmss; 
    u_int32_t  tcpi_reordering; 

    u_int32_t  tcpi_rcv_rtt; 
    u_int32_t  tcpi_rcv_space; 

    u_int32_t  tcpi_total_retrans; 
}; 

Można zauważyć, że mój skrypt zwraca tylko liczbę całkowitą. Oto C enum, które wyszczególnia stany TCP i ich wartości całkowite. Ponownie, to stwierdzono w /usr/include/netinet/tcp.h

enum 
{ 
    TCP_ESTABLISHED = 1,   
    TCP_SYN_SENT, 
    TCP_SYN_RECV, 
    TCP_FIN_WAIT1, 
    TCP_FIN_WAIT2, 
    TCP_TIME_WAIT, 
    TCP_CLOSE, 
    TCP_CLOSE_WAIT, 
    TCP_LAST_ACK, 
    TCP_LISTEN, 
    TCP_CLOSING /* now a valid state */ 
}; 

Również ten thread mówi, że można wykryć CLOSE_WAIT odczytując EOF. Ale ponieważ obawiasz się, że dane zostały wysłane, prawdopodobnie będziesz musiał rozpakować do tcpi_last_data_sent.

Wreszcie, zastrzeżenie. Podjąłem wyzwanie, by odpowiedzieć na twoje pytanie, ponieważ brzmiało to zabawnie i było, ale moje nogi C wciąż są chwiejne, więc YMMV. :)