なぜかconnection timeoutが発生しまくる事象が起きてその際の再送をみるみたいなことをしたくてコンテナで動かせるようのやつ。仕事で使うことは滅多にない気がするがサッとあると便利。(ChatGPTだと頑なにIO::Socket::INETを使ってくれなくて微妙に困った)
#!/usr/bin/perl use strict; use warnings; use IO::Socket::INET; # --- 対象のリモートホストとポート --- # コマンドライン引数で指定(例: ./tcp_syn_procfs.pl 192.168.1.1 80) my $remote_ip = $ARGV[0] // '192.168.1.1'; my $remote_port = $ARGV[1] // 80; # --- TCP接続の試行(内部でSYNを送信) --- my $socket = IO::Socket::INET->new( PeerAddr => $remote_ip, PeerPort => $remote_port, Proto => 'tcp', Timeout => 2, ); if ( !$socket ) { print "接続失敗 ($remote_ip:$remote_port): $!\n"; # --- /proc/net/snmp から TCP 再送メトリクスの取得 --- if ( open( my $snmp_fh, '<', '/proc/net/snmp' ) ) { my @lines = <$snmp_fh>; close($snmp_fh); my ( $tcp_header_line, $tcp_value_line ); # /proc/net/snmp には "Tcp:" という2行セットがあるので探す for ( my $i = 0 ; $i < @lines ; $i++ ) { if ( $lines[$i] =~ /^Tcp:\s*(.*)/ ) { $tcp_header_line = $1; if ( $i + 1 < @lines and $lines[ $i + 1 ] =~ /^Tcp:\s*(.*)/ ) { $tcp_value_line = $1; last; } } } if ( $tcp_header_line && $tcp_value_line ) { my @headers = split( /\s+/, $tcp_header_line ); my @values = split( /\s+/, $tcp_value_line ); my $found = 0; for ( my $i = 0 ; $i < @headers ; $i++ ) { if ( $headers[$i] eq 'RetransSegs' ) { print "TCP RetransSegs: $values[$i]\n"; $found = 1; last; } } print "RetransSegs フィールドが見つかりませんでした。\n" unless $found; } else { print "TCP メトリクス情報が見つかりませんでした。\n"; } } else { warn " /proc/net/snmp をオープンできません: $!\n"; } } else { print "接続成功 ($remote_ip:$remote_port)\n"; close($socket); }
ついでにRuby版も書いてもらった。仕事で使っていたコンテナにRubyは入ってなかったので試してはないです。
#!/usr/bin/env ruby require 'socket' require 'timeout' # --- 対象のリモートホストとポート --- remote_ip = ARGV[0] || '192.168.1.1' remote_port = (ARGV[1] || '80').to_i begin # タイムアウト付きでTCP接続を試みる(内部的にSYN送信) Timeout.timeout(2) do socket = TCPSocket.new(remote_ip, remote_port) puts "接続成功 (#{remote_ip}:#{remote_port})" socket.close exit 0 end rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::ENETUNREACH, Timeout::Error => e puts "接続失敗 (#{remote_ip}:#{remote_port}): #{e.message}" # --- /proc/net/snmp から TCP 再送メトリクスの取得 --- begin lines = File.readlines('/proc/net/snmp') tcp_header_line = nil tcp_value_line = nil lines.each_with_index do |line, idx| if line.start_with?("Tcp:") # 最初の "Tcp:" 行をヘッダー行とし、次の行を値行とする unless tcp_header_line tcp_header_line = line.split[1..-1] # "Tcp:" を除く if idx + 1 < lines.size && lines[idx + 1].start_with?("Tcp:") tcp_value_line = lines[idx + 1].split[1..-1] end break end end end if tcp_header_line && tcp_value_line index = tcp_header_line.index("RetransSegs") if index puts "TCP RetransSegs: #{tcp_value_line[index]}" else puts "RetransSegs フィールドが見つかりませんでした。" end else puts "TCP メトリクス情報が見つかりませんでした。" end rescue => ex warn "/proc/net/snmp を読み込めませんでした: #{ex.message}" end rescue => e warn "予期しないエラーが発生しました: #{e.message}" end