Rubyで簡易TCPサーバ

特定のTCPポートにbindしてくれるだけの簡単なものが無いかな、と思っていたらRubyですぐ書けるようだ。

ということで、これを使ってみた。

プログラム

#!/usr/bin/ruby

require "socket"
gs = TCPServer.open(ARGV[0])
addr = gs.addr
addr.shift
printf("server is on %s\n", addr.join(":"))

while true
  Thread.start(gs.accept) do |s|
    print(s, " is accepted\n")
    while s.gets
      s.write($_)
    end
    print(s, " is gone\n")
    s.close
  end
end

試してみる

ターミナルを2つ開き、片方でTCPサーバを起動。

$ ./tcpserver.rb 5000
server is on 5000:0.0.0.0:0.0.0.0

もう片方でnetstatで見てみると、確かにLISTENしている。

$ netstat -an|grep 5000
tcp4       0      0  *.5000                 *.*                    LISTEN

接続して文字列を打ち込んでみると、そのまま返ってくるechoサーバになっている。

$ telnet localhost 5000
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
AAA
AAA
BBB
BBB
Connection closed by foreign host.

well-known portの壁

このプログラムは、ポート番号1024までは一般ユーザで実行できるけど、1024未満では実行できない。well-known portにbindするにはroot権限が必要なため。

$ ./tcpserver.rb 1024
server is on 1024:0.0.0.0:0.0.0.0

$ ./tcpserver.rb 1023
./tcpserver.rb:4:in `initialize': Permission denied - bind(2) (Errno::EACCES)
	from ./tcpserver.rb:4:in `open'
	from ./tcpserver.rb:4