Help us understand the problem. What is going on with this article?

RubyでTCP通信 on windows

More than 1 year has passed since last update.

RubyでTCPサーバー/クライアントを作ってみる

サンプルをコピペしただけだと上手く動かないor微妙な点がいくつかあったので備忘録です。

サーバー

# server
require 'socket'
# 3030番ポートを開く
gs = TCPServer.open(nil, 3030)
socks = [gs]

puts "server is on #{gs.addr}"

loop {
  nsock = select(socks)
  next unless nsock[0]
  nsock[0].each do |s|
    if s == gs
      ns = s.accept
      socks.unshift ns
      puts "#{ns} is accept"
    else
      if s.eof?
        puts "#{s} is gone."
        s.close
        socks.delete(s)
      else
        msg = s.readpartial(4 * 1024)
        p msg
      end
      break
    end
  end
}

クライアント

# client
require 'socket'

s = TCPSocket.open("localhost", 3030)
while msg = gets
  puts "write #{msg}"
  s.write msg
end

仕様を変更した点

  • サーバー側の通信読み込み部分をs.getsからs.readpartialへ変更
    文字列ならばいいのかもしれないが、今後バイト列を書き込み/読み込みを考えるとgetsではダメな可能性がある。
  • サーバー側のaccept時にsocks.pushではなくsocks.unshiftを用いTCPServerソケットの優先度を下げた
  • select後TCPSocketに対して通信を行ったあとはbreakで再度selectへ移行するようにした。
    上2つはwindows特有のバグなのかは分かりませんが、readpartial時に指定した以上の長さの通信がある場合
    次回のselectで、どういうわけかTCPServerが読み込み待ちになるバグへの対処です。

反省

s.nreadでブロックなしに読み取れるバイト数が取れるのでコレを使うといいかもしれない。
但し、タイミング次第でやはりselectのバグ?を踏むと思われるので待ち行列の優先度等については考慮する必要がある。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away