Можно ли узнать, находится ли рубиновый сокет в состоянии ESTABLISHED или CLOSE_WAIT без фактической отправки или чтения данных? - PullRequest
5 голосов
/ 18 мая 2009
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

С этого момента я хотел бы проверить в потоке, является ли соединение ssl и нижележащий сокет по-прежнему ESTABLISHED или оно вошло в CLOSE_WAIT после закрытия по умолчанию 7200 секунд или, что еще хуже, без необходимости .write() до или .read() от него.

Это делается с помощью select(), IO.select() или другим методом?

Кстати: сокет никогда не получает никаких данных, которые он иногда отправляет.

1 Ответ

10 голосов
/ 06 июня 2009

Ответ зависит от реализации . Вам нужно будет проверить заголовочные файлы реализации tcp в вашей ОС. Вот пример клиента для Linux, который возвращает состояние сокета.

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

Вот структура tcp_info для моего современного 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;
};

Вы можете заметить, что мой скрипт возвращает только целое число. Вот перечисление C, которое детализирует состояния TCP и их целочисленные значения. Опять же, это было найдено в /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 */
};  

Кроме того, этот поток говорит, что вы можете определить CLOSE_WAIT, прочитав EOF. Но так как вы беспокоитесь о том, были ли отправлены данные, вам, вероятно, потребуется распаковать в tcpi_last_data_sent.

Наконец, предостережение. Я взял на себя задачу ответить на ваш вопрос, потому что это звучало забавно, и это было, но мои ноги С все еще колеблются, поэтому YMMV. :)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...