2009-05-18 5 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 aquí me gustaría comprobar en un hilo si la conexión SSL y la toma subyacente sigue siendo ESTABLISHED o si entró en CLOSE_WAIT después del default de 7200 segundos o incluso peor consiguieron cerrados, pero sin necesidad de .write() a o .read() desde él.¿es posible averiguar si un conector Ruby está en estado ESTABLISHED o CLOSE_WAIT sin enviar o leer datos?

¿Se hace con select(), IO.select() u otro método?

BTW: El zócalo nunca recibe datos que envía ocasionalmente.

Respuesta

9

La respuesta es implementation specific. Deberá verificar los archivos de encabezado de implementación tcp en su sistema operativo. Aquí hay un cliente de muestra para Linux que devuelve el estado del 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}" 

Aquí está la estructura tcp_info para mi hasta a la fecha de linux ubuntu

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

Es posible observar que mi script sólo devuelve un entero. Aquí está la C enumeración que detalla los estados TCP y sus valores enteros. De nuevo, esto se encontró en /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 */ 
}; 

Además, este thread dice que se puede detectar mediante la lectura de CLOSE_WAIT EOF. Pero dado que le preocupa si se han enviado datos, es probable que deba desempaquetar hasta tcpi_last_data_sent.

Finalmente, una advertencia. Asumí el desafío de responder a tu pregunta porque sonaba divertido y lo era, pero mis piernas C todavía están tambaleantes así que YMMV. :)

Cuestiones relacionadas