Ruby Socket プログラミング

Ruby はネットワークにアクセスするための2つのレベルのサービスを提供します。低レベルではオペレーティングシステムにアクセスでき、接続指向およびコネクションレスプロトコルに対するクライアントとサーバーの基本的なソケットサポートを実装できます。

Ruby は FTP、HTTP などのアプリケーションのネットワークプロトコルを統一的にサポートします。

高レベルのものでも低レベルのものでも、Ruby はいくつかの基本クラスを提供し、TCP、UDP、SOCKS などの多くのプロトコルとやり取りできるようにします。ネットワーク層にこだわる必要はありません。これらのクラスは、サーバーへの読み書きを簡単に行うためのヘルパークラスも提供します。

それでは、Ruby Socket プログラミングの方法を学んでいきましょう。


Sockets とは

アプリケーション層がトランスポート層を介してデータ通信を行う際、TCP と UDP は同時に複数のアプリケーションプロセスに並行サービスを提供するという問題に直面します。複数の TCP 接続または複数のアプリケーションプロセスが、同じ TCP プロトコルポートを介してデータを転送する必要がある場合があります。異なるアプリケーションプロセスと接続を区別するために、多くのコンピュータオペレーティングシステムは、アプリケーションが TCP/IP プロトコルとやり取りするためのソケット (Socket) と呼ばれるインターフェースを提供し、異なるアプリケーションプロセス間のネットワーク通信と接続を区別します。

ソケットを生成するには、主に3つのパラメータがあります: 通信の宛先 IP アドレス、使用するトランスポート層プロトコル (TCP または UDP)、および使用するポート番号です。Socket の本来の意味は「コンセント」です。これら3つのパラメータを組み合わせて、1つの「コンセント」Socket にバインドすることで、アプリケーション層はトランスポート層とソケットインターフェースを介して、異なるアプリケーションプロセスやネットワーク接続からの通信を区別し、データ転送の並行サービスを実現できます。

Sockets 用語解説:

オプション説明
domain使用するプロトコルファミリを指定します。通常は PF_INET、PF_UNIX、PF_X25 などです。
typesocket のタイプを指定します: SOCK_STREAM または SOCK_DGRAM。Socket インターフェースは raw Socket (SOCK_RAW) も定義しており、プログラムが低層プロトコルを使用することを許可します。
protocol通常は 0 を割り当てます。
hostnameネットワークインターフェースの識別子:
  • 文字列。ホスト名または IP アドレスを指定できます。
  • 文字列 "<broadcast>" は、INADDR_BROADCAST アドレスを指定します。
  • 長さ 0 の文字列は、INADDR_ANY を指定します。
  • 整数は、ホストバイトオーダーのバイナリアドレスとして解釈されます。
portport はポートの番号です。各サーバーはクライアント接続のために1つ以上のポート番号をリッスンします。ポート番号は Fixnum のポート番号で、サーバー名とポートを含みます。

シンプルなクライアント

以下では、指定されたホストとポートを使用して簡単なクライアントの例を作成します。Ruby の TCPSocket クラスは socket を開くための open メソッドを提供します。

TCPSocket.open(hosname, port) は TCP 接続を開きます。

Socket 接続を開くと、IO オブジェクトのように読み取ることができます。完了したら、ファイルを閉じるように接続を閉じる必要があります。

次の例は、指定されたホストに接続し、socket からデータを読み取り、最後に socket を閉じる方法を示しています。

例

require 'socket' #Sockets は標準ライブラリです hostname = 'localhost' port = 2000 s = TCPSocket.open(hostname, port) while line = s.gets #socket から各行のデータを読み取ります puts line.chop #端末に出力します end s.close #socket を閉じます

シンプルなサーバー

Ruby では、TCPServer クラスを使用して簡単なサーバーを作成できます。TCPServer オブジェクトは TCPSocket のファクトリオブジェクトです。

次に、TCPServer.open(hostname, port) を使用して TCPServer オブジェクトを作成します。

次に、TCPServer の accept メソッドを呼び出します。このメソッドは、クライアントが指定されたポートに接続するまで待機し、そのクライアントに接続されたことを示す TCPSocket オブジェクトを返します。

例

require 'socket' #socket 標準ライブラリを取得 server = TCPServer.open(2000) #Socket はポート 2000 をリッスンします loop { #サービスを永久に実行します client = server.accept #クライアント接続を待機します client.puts(Time.now.ctime) #クライアントに時刻を送信します client.puts "Closing the connection. Bye!" client.close #クライアント接続を閉じます }

では、サーバー上で上記のコードを実行して、結果を確認してください。


マルチクライアントTCPサーバー

インターネット上では、ほとんどのサービスが多数のクライアント接続を持っています。

Ruby の Thread クラスを使用すると、マルチスレッドサービスを簡単に作成できます。1つのスレッドがクライアント接続を処理し、メインスレッドはさらなる接続を待機します。

例

require 'socket' #socket 標準ライブラリを取得 server = TCPServer.open(2000) #Socket はポート 2000 をリッスンします loop { #サービスを永久に実行します Thread.start(server.accept) do |client| client.puts(Time.now.ctime) #クライアントに時刻を送信します client.puts "Closing the connection. Bye!" client.close #クライアント接続を閉じます end }

この例では、socket は永久に実行されます。server.accept がクライアント接続を受け取ると、新しいスレッドが作成され、すぐにリクエストの処理を開始します。メインプログラムはすぐにループして新しい接続を待機します。


ミニ Web ブラウザ

socket ライブラリを使用して、あらゆるインターネットプロトコルを実装できます。次のコードは、Web ページのコンテンツを取得する方法を示しています。

例

require 'socket' host = 'www.w3cschool.cc' #Web サーバー port = 80 #デフォルトの HTTP ポート path = "/index.htm" #取得したいファイルのアドレス #これは HTTP リクエストです request = "GET #{path} HTTP/1.0\r\n\r\n" socket = TCPSocket.open(host,port) #サーバーに接続します socket.print(request) #リクエストを送信します response = socket.read #完全なレスポンスを読み取ります # Split response at first blank line into headers and body headers,body = response.split("\r\n\r\n", 2) print body #結果を出力します

Web のようなクライアントを実装するには、Net::HTTP など、HTTP 用に事前に構築されたライブラリを使用できます。

次のコードは、前述のコードと同等です。

例

require 'net/http' #必要なライブラリ host = 'www.w3cschool.cc' #Web サーバー path = '/index.htm' #必要なファイル http = Net::HTTP.new(host) #接続を作成 headers, body = http.get(path) #ファイルをリクエスト if headers.code == "200" #ステータスコードを確認 print body else puts "#{headers.code} #{headers.message}" end

以上、Ruby における socket の応用について簡単に紹介しました。詳細なドキュメントは以下を参照してください。Ruby Socket ライブラリとクラスメソッド

その他の拡張