Rubyで echo サーバを作ろうと思い調べたところ、 TCPServer クラスがありました。
class TCPServer (Ruby 3.3 リファレンスマニュアル)
リファレンスマニュアルには echo サーバの実装が記載されていました。
もう少し調べてみたところ、RubyKaigi 2009 の資料「ソケットライブラリの改善」がありました。
ソケットライブラリの改善 - 日本Ruby会議2009
この資料を読んだところ、TCPServer を使うよりは Socket.tcp_server_loop を使うほうが良さそうでした。
Socket.tcp_server_loop (Ruby 3.3 リファレンスマニュアル)
そこで、 Socket.tcp_server_loop で echo サーバを作り、その通信を ngrep で確認してみたので、メモを残します。
目次
環境
- WSL2
- Ruby 3.3.6
echo サーバの実装
Socket.tcp_server_loop を使って echo サーバを実装します。ポートは 12345 で待ち受けます。
なお、ブロックに渡されてくるソケットオブジェクトのクラスやメッセージの中身を確認するようなコードも入れています。
# tcp_echo_server.rb require 'socket' PORT = '12345' Socket.tcp_server_loop(PORT) do |sock, addr_info| p sock.class #=> Socket message = sock.recv 1000 p message # => "hello\n" p message.class #=> String sock.sendmsg message ensure sock.close end
ngrepをインストールする
echoサーバの通信内容を確認するため、今回はお手軽な ngrep を使います。
WSL2のUbuntuでは ngrep が未インストールだったため、インストールしておきます。
$ sudo apt install ngrep
ngrepでechoサーバの通信内容を確認する
まず、1つ目のターミナルで echo サーバを起動します。
$ ruby tcp_echo_server.rb
続いて、2つ目のターミナルを起動します。
ngrep で通信内容をキャプチャするために、ネットワークインタフェースを ip コマンドで確認しました。
$ ip -br -4 address lo UNKNOWN 127.0.0.1/8 eth0 UP ***.***.***.***/*** br-*** DOWN ***.***.***.***/*** docker0 DOWN ***.***.***.***/***
今回の場合は lo を使えば良さそうなので、 ngrep を実行します。
$ sudo ngrep -x -q -d lo '' 'port 12345' [sudo] user のパスワード: interface: lo (127.0.0.0/255.0.0.0) filter: ( port 12345 ) and ((ip || ip6) || (vlan && (ip || ip6)))
最後に、3つ目のターミナルにて、 nc コマンドで echo サーバへメッセージ hello を投げます。すると、 hello という返信が返ってきました。
$ echo hello | nc localhost 12345 hello
1つ目のターミナルを確認すると、いくつかの値が出力されていました。
Socket "hello\n" String
2つ目のターミナルでは、 hello メッセージのやり取りが出力されていました。
T 127.0.0.1:54122 -> 127.0.0.1:12345 [AP] #4 68 65 6c 6c 6f 0a hello. T 127.0.0.1:12345 -> 127.0.0.1:54122 [AP] #6 68 65 6c 6c 6f 0a hello.
以上で、 echo サーバとの通信を ngrep で確認することができました。
ソースコード
GitHubに上げました。
https://github.com/thinkAmi-sandbox/tcp_servers_by_ruby
今回のプルリクはこちら。
https://github.com/thinkAmi-sandbox/tcp_servers_by_ruby/pull/1