【コラム】

Hello Worldコレクション

12 今まで試した言語でソケットプログラミング - ネットワークサーバ編

    山森丈範  [2008/07/25]

    ネットワークサーバのHello World

    第12回は少し趣向を変えて、ネットワークサーバのHello Worldです。具体的には、socketを使って所定のTCPのポートへの接続を待ち受け、そのポートへの接続が行われると、接続相手のクライアントに対してHello Worldのメッセージを返すようなプログラムを作成します。

    C言語の場合

    ネットワークサーバのHello WorldをC言語で記述すると、リスト1のようになります。ここでは、プログラム本体の記述がわかりやすいように、エラー処理はあえて省略しています。

    リスト1 C言語の場合(socket_c_lang.c)

    #include <sys/types.h>        ← socket()を使うために必要
    #include <sys/socket.h>       ← socket()を使うために必要
    #include <netinet/in.h>       ← INETドメインソケットを使うため
    #include <unistd.h>           ← write()のため
    #include <string.h>           ← memset()のため
    
    int
    main()
    {
      int sv, sv_ac;              ← socket()用とaccept()用のファイル記述子
      struct sockaddr_in addr;    ← INETドメインのソケットアドレス
      int optval = 1;             ← setsockopt()で使用
    
      sv = socket(PF_INET, SOCK_STREAM, 0);      ← INETドメインのTCPソケットを作成
      setsockopt(sv, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval);
                                                 ↑ ソケットアドレスの再利用を許可
      memset(&addr, 0, sizeof addr);             ← ソケットアドレスをゼロ初期化
      addr.sin_family = AF_INET;                 ← INETドメインを指定
      addr.sin_addr.s_addr = htonl(INADDR_ANY);  ← IPアドレスは任意
      addr.sin_port = htons(12345);              ← ポート番号は12345
      bind(sv, (struct sockaddr *)&addr, sizeof addr);  ← ソケットアドレスを指定
    
      listen(sv, SOMAXCONN);                     ← ソケットをLISTEN状態にする
      sv_ac = accept(sv, 0, 0);                  ← 接続を受け付ける
    
      write(sv_ac, "Hello World\n", 12);         ← 接続相手にメッセージを出力
    
      return 0;
    }
    

    ネットワークサーバに接続テスト

    ネットワークサーバの動作を確認するためには、クライアント側のコマンドも必要です。これには、telnetコマンドまたはnc(netcat)コマンドを使います。なお、telnetコマンドなどは使いますが、TELNETプロトコルでログインするわけではありません。

    まずは、実行例1のように、サーバー側を実行します。ここで、別の端末ウィンドウに切り替え、そこからクライアント側のコマンドとして実行例2のように実行します。すると、自分自身のホストであるlocalhostの、TCPの12345番ポートに接続が行われます。その直後、サーバからHello Worldのメッセージが返って来て、接続が終了します。

    実行例1 ネットワークサーバの実行

    $ ./socket_c_lang          ← カレントディレクトリの実行ファイルを実行する
                               ← この状態で、別の端末ウィンドウ等から実行例2を実行
    $                          ← 実行例2を実行後、シェルのプロンプトに戻る
    

    実行例2 ネットワークサーバに接続テスト

    $ telnet localhost 12345            ← localhostのTCPの12345番ポートに接続
    Trying 127.0.0.1...
    Connected to localhost.             ← 接続確立
    Escape character is '^]'.
    Hello World                         ← サーバプログラムからのメッセージ
    Connection closed by foreign host.  ← 接続終了
    $                                   ← シェルのプロンプトに戻る
    

    Perlの場合

    Perlを使って記述すると、リスト2のようになります。同じく、エラー処理は省略しています。このように、socket、bindなどの関数名や、PF_INETなどの定数ラベルはC言語のものと同じであり、プログラム全体がC言語と似ていることがわかります。

    リスト2 Perlの場合(socket_perl)

    #!/usr/bin/perl
    
    use Socket;                                  ← Socketモジュールを使用
    
    socket(sv, PF_INET, SOCK_STREAM, 0);         ← INETドメインのTCPソケットを作成
    setsockopt(sv, SOL_SOCKET, SO_REUSEADDR, 1); ← ソケットアドレスの再利用を許可
    bind(sv, sockaddr_in(12345, INADDR_ANY));    ← ポート番号12345、IPアドレス任意
    listen(sv, SOMAXCONN);                       ← ソケットをLISTEN状態にする
    accept(sv_ac, sv);                           ← 接続を受け付ける
    print sv_ac "Hello World\n";                 ← 接続相手にメッセージを出力
    

    Javaアプリケーションの場合

    Javaアプリケーションで記述したサーバプログラムはリスト3のとおりです。このように、ServerSocketクラスを使ってソケットを作成し、accept()したあと、PrintWriterクラスのprint()メソッドを使って文字列を出力します。

    リスト3 Javaアプリケーションの場合(SocketJava.java)

    import java.io.*;             ← PrintWriterを使うため
    import java.net.*;            ← Socketを使うため
    
    public class SocketJava {
      public static void main(String[] args) {
        try {
          ServerSocket sv = new ServerSocket(12345);  ← サーバソケットを作成
          Socket sv_ac = sv.accept();                 ← 接続を受け付ける
          PrintWriter out = new PrintWriter(sv_ac.getOutputStream());
          out.print("Hello World\n");               ←↑ 接続相手にメッセージを出力
          out.flush();                                ← 出力をフラッシュする
        } catch (Exception e) {}                      ← エラー処理は省略
      }
    }
    

    Pythonの場合

    Pythonを使う場合はリスト4のようになります。コーディングは、Perlに類似したものとなっています。

    リスト4 Pythonの場合(socket_python)

    #!/usr/bin/python
    
    from socket import *                         ← socketモジュールをインポート
    
    sv = socket(AF_INET, SOCK_STREAM)            ← INETドメインのTCPソケットを作成
    sv.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)   ← ソケットアドレスの再利用を許可
    sv.bind(('', 12345))                         ← ポート番号12345、IPアドレス任意
    sv.listen(SOMAXCONN)                         ← ソケットをLISTEN状態にする
    (sv_ac, cl_addr) = sv.accept()               ← 接続を受け付ける
    sv_ac.send('Hello World\n')                  ← 接続相手にメッセージを出力
    

    Rubyの場合

    Rubyでは、TCPserverが使えるため、コードの行数が少なくなります(リスト5)。acceptの前のlistenは不要です。

    リスト5 Rubyの場合(socket_ruby)

    #!/usr/bin/ruby
    
    require 'socket'                  ← socketライブラリをロード
    
    sv = TCPserver.open('', 12345)    ← ポート番号12345のTCPのサーバソケットを作成
    sv_ac = sv.accept                 ← 接続を受け付ける
    sv_ac.write("Hello World\n")      ← 接続相手にメッセージを出力
    

    Tclの場合

    Tcl/Tkのスクリプト部分であるTcl(tclsh)を使うと、リスト6のようになります。まず、接続時に呼び出されるプロシジャを定義し、Tclの組み込みコマンドのsocketの引数で、そのプロシジャとポート番号を指定します。

    リスト6 Tclの場合(socket_tcl)

    #!/usr/bin/tclsh
    
    proc accept {sv_ac cl_addr cl_port} {   ← 接続時に呼び出されるプロシジャを定義
      puts $sv_ac {Hello World}             ← 接続相手にメッセージを出力
      close $sv_ac                          ← 接続をクローズ
      exit 0                                ← 1回の接続でサーバを終了する
    }
    
    socket -server accept 12345  ← プロシジャ/ポート番号指定でサーバソケットを作成
    vwait forever                ← イベント(接続)を待つ
    
    関連したタグ

    新着記事

    特設サイトの情報

      求人情報

      人気記事

      一覧

      イチオシ記事

      新着記事

      特別企画

      転職ノウハウ

      あなたの仕事適性診断

      4つの診断で、自分の適性を見つめなおそう!

      Heroes File ~挑戦者たち~

      働くこと・挑戦し続けることへの思いを綴ったインタビュー

      はじめての転職診断

      あなたにピッタリのアドバイスを読むことができます。

      転職Q&A

      転職に必要な情報が収集できます

      スカウト転職する

      企業からアプローチのメッセージが届きます。

      マイナビニュースマガジン