2009-05-18 16 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 

A partir de là, je voudrais vérifier dans un fil si la connexion ssl et la prise sous-jacente est encore ESTABLISHED ou s'il est entré en CLOSE_WAIT après le défaut de 7200 secondes ou même pire a été fermé sans avoir réellement .write() à ou .read() à partir de celui-ci.est-il possible de savoir si une socket ruby ​​est dans l'état ESTABLISHED ou CLOSE_WAIT sans réellement envoyer ou lire des données?

Est-ce fait avec select(), IO.select() ou une autre méthode?

BTW: Le socket ne reçoit jamais de données qu'il n'en envoie que de temps en temps.

Répondre

9

La réponse est implementation specific. Vous devrez vérifier les fichiers d'en-tête de l'implémentation de tcp sur votre système d'exploitation. Voici un exemple de client pour linux qui retourne l'état du socket.

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}" 

Voici le struct tcp_info pour ma mise à jour 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; 
}; 

Vous pouvez noter que mon script retourne uniquement un entier. Voici le C enum qui détaille les états TCP et leurs valeurs entières. Encore une fois, cela a été trouvé dans /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 */ 
}; 

En outre, ce thread dit que vous pouvez détecter CLOSE_WAIT en lisant EOF. Mais comme vous êtes préoccupé par l'envoi de données, vous devrez probablement décompresser jusqu'à tcpi_last_data_sent.

Enfin, une mise en garde. J'ai relevé le défi de répondre à ta question parce que ça avait l'air amusant et c'était mais mes jambes en C sont encore bancales donc YMMV. :)