socket server & client ( 以 unix domain socket 為例 )


#1

單純工作上面有特殊需求,有一個 service 的 process 為 daemon,stdin / stdout 都在 watch dog 上,無法開 http 這種可能會對外的服務,且希望 limit 為 1 : 1 傳輸 … 思考了一下最方便的應該還是 unix domain socket …

以下為 demo code,首先是 server 端

#[[server.rb]]

require 'securerandom'
require "socket"

path = "#{__dir__}/socket.sock"
File.unlink(path) if File.exists?(path)
server = UNIXServer.new(path)
server_serial = SecureRandom.hex(2)

puts "Server start(#{server_serial})"

loop do
  socket = server.accept
  job_serial = SecureRandom.hex(2)
  begin
    while (message = socket.readline) != "\r\n"
      puts "Server rev(  #{job_serial}) : [#{message.strip}]"
    end
    10.times do |i|
      sleep(1)
      message = "server(#{server_serial}) : job(#{job_serial}) : index(#{i}) : message(#{SecureRandom.hex(8)})"
      puts "Server send( #{job_serial}) : [#{message}]"
      socket.write(message)
      socket.write("\r\n") # EOF(break)
    end
    socket.write("\r\n") # EOF(finished)
  rescue EOFError , Errno::EPIPE
    puts "Server close(#{job_serial}) : [client close connection(ERR) : #{$!}]"
  ensure
    puts "Server close(#{job_serial}) : [close client connection]"
    socket.close
  end
end

再來是 client 端

require 'securerandom'
require "socket"

path = "#{__dir__}/socket.sock"

socket = UNIXSocket.new(path)
client_serial = SecureRandom.hex(2)

puts "Client start(#{client_serial})"

begin
  10.times do |i|
    sleep(1)
    message = "client(#{client_serial}) : index(#{i}) : message(#{SecureRandom.hex(8)})"
    puts "Client send( #{client_serial}) : [#{message}]"
    socket.write(message)
    socket.write("\r\n") # EOF(break)
  end
  socket.write("\r\n") # EOF(finished)
  while (message = socket.readline) != "\r\n"
    puts "Client rev(  #{client_serial}) : [#{message.strip}]"
  end
rescue EOFError , Errno::EPIPE
  puts "Client close(#{client_serial}) : [server close connection(ERR) : #{$!}]"
ensure
  puts "Client close(#{client_serial}) : [close server connection]"
  socket.close
end

unix domain socket 的詳細略過,大概就是用一個檔案建立 socket 連線,而非過 TCP/IP 之類的,所以也不需要 IP / port 那些鬼東西的設定,但前提是必須同台主機就是 << 當然這也是安全性考量 / 使用它的原因之一

其實這種東西自幹應該都不是問題(其實你就是在寫 http server 哩)怕的都是變數污染就是,所以上面都有列 server / job 的 serial 來做檢查,有需要的人可以玩看看唄,先開 server 再開多支 client 就可以交互測試之類的(以這 demo 兩個檔案要放在一起,才吃得到共用的 socket.sock),而 server 要附加到別的 process 內的話,多開支 thread 來處理即可,然而其實沒有那麼龜毛的要求的話,開 sinatra 之類的會方便些就是了(當然缺點應該是 sinatra 可能會去砍別的 thread,即使不是它自己產生的|||… 這點請小心就是||||)