ユーザ用ツール

サイト用ツール


alworker:tcp_ipサーバー

文書の過去の版を表示しています。


AlWorker TCP/IPサーバー

require "al_worker_tcp"


TCPサーバーを作成する機能です。SMTPサーバのような、chat式のサーバ機能を実装しています。

サンプル

サーバー

tcp_server.rb
require "al_worker_tcp"
 
class TcpServer < AlWorker
 
  # イニシャライザでTCPを用意する。
  def initialize2()
    @tcp = Tcp.new( "<any>", 10025 ) # リスンアドレス、ポート番号を指定。
    @tcp.run( self )
  end
 
  # helloコマンド
  #  "helo localhost"
  def tcp_helo( sock, param )
    sock.puts "250 hello welcome."
    return true
  end
 
  # mailコマンド
  #  "mail from: <nobody@example.com>"
  def tcp_mail( sock, param )
    if /^from: ?(.+)$/ =~ param[""]
      sock.puts "250 Ok"
    else
      sock.puts "501 Syntax error."
    end
    return true
  end
end
 
server = TcpServer.new("tcp_server")
server.parse_option()
server.daemon()

クライアント(以下の例は、Ruby基本機能のみ使用した例で、Aloneライブラリは使わず実装しています)

tcp_client.rb
require "socket"
 
sock = TCPSocket.open("localhost", 10025)
 
puts 'SEND "helo"'
sock.puts "helo"
puts 'RECEIVE ' + sock.gets
 
puts 'SEND "quit"'
sock.puts "quit"
puts 'RECEIVE ' + sock.gets
 
sock.close

実行結果

% ruby tcp_client.rb
SEND "helo"
RECEIVE 250 hello welcome.
SEND "quit"
RECEIVE 200 OK quit.

解説

AlWorkerを継承したクラスに “tcp_” をプレフィックスとして付与したメソッドを定義すると、フレームワークにTCPコマンドとして認識されます。
メソッドには、接続ソケット sock と、パラメータ param が渡されます。
パラメータはJSONパースされ、paramには結果のHashが渡されます。JSONパースできなかった場合は、param[""]にパース前の文字列が入ります。
返り値に trueを指定すると継続してコマンドを受けつけ、falseを指定すると接続を切ります。
デフォルトで、接続を切るためのコマンド、"quit"が定義されています。
定義されていないコマンドが送られた場合、"501 Error Command not implemented." を返します。

同期/非同期

イベントハンドラはデフォルトで同期的に呼び出され、たとえば2つのクライアントから同時にコマンドを受信しても、一つずつ実行します。
非同期にしたい場合は、”tcp_a_” をプレフィックスとして付けます。

  def tcp_a_xxxx( sock, param )
    # any code
    return true
  end

サービスモデル(スレッド/プロセス)

デフォルトで、スレッドモデルで動作します。
接続ごとに別プロセスで動作させる(プロセスモデル)には、以下のように指定します。

    @tcp.mode_service = :process

chat以外のプロトコルを使用

chat方式ではないプロトコルを使いたい場合は、AlWorker::Tcpクラスを継承して、_start_service()メソッドをオーバライドします。

すべてのGETリクエストに "It works!" と返すウェブサーバ

class WebServer < AlWorker::Tcp
 
  def _start_service( sock )
    req = []
    while txt = sock.gets
      txt.chomp!
      break  if txt.empty?
      req << txt
    end
 
    if !req.empty? && req[0].upcase.start_with?("GET ")
      sock.puts "HTTP/1.0 200 OK\r\n"
      sock.puts "Content-Type: text/html\r\n"
      sock.puts "\r\n"
      sock.puts "<!DOCTYPE html>\r\n"
      sock.puts "<title>TESTPAGE</title>\r\n"
      sock.puts "<p>It works!</p>\r\n"
    end
 
  rescue Exception => ex
    raise ex  if ex.class == SystemExit 
    AlWorker.log( ex )
 
  ensure
    sock.close if ! sock.closed?
  end
end
 
 
class TcpServer < AlWorker
 
  def initialize2()
    @tcp = WebServer.new( "<any>", 10080 ) # リスンアドレス、ポート番号を指定。
    @tcp.run( self )
  end
 
end
 
server = TcpServer.new( "web_server" )
server.daemon()
alworker/tcp_ipサーバー.1633398480.txt.gz · 最終更新: 2021/10/05 10:48 by hirohito