ソケットプログラミング

by 菊地時夫 last modified 2009-06-16 10:09

演習1

UNIX のプロセス間通信

  • パイプ
  • FIFO (名前付きパイプ)
  • ソケット
  • 共有メモリ
  • etc. etc.

パイプ

  • ターミナルを2つ立ち上げる
  • 一方で、次のコマンドを実行
    • cat /usr/share/dict/words | more
  • もう一方で、次のコマンドを実行
    • ps
  • 終了は
    • cat ... 実行ターミナルで q

パイプの実験結果考察

  • cat /usr/share/dict/words | more は2つのプロセスが実行されている
  • cat の標準出力が more の標準入力に渡されている

FIFO

  • First-In First-Out
  • mkfifo /tmp/mypipe で FIFO (名前付きパイプ) を作成
  • 一方のターミナルで
    • cat /usr/share/dict/words > /tmp/mypipe
  • もう一方で、
    • more /tmp/mypipe
    • こちらを q で終了すると cat も終了する

socket

以下の実験は

  • 作業ディレクトリ ~/net を作成し、その中で行う:
       $ cd
       $ mkdir net
       $ cd net
    

何を作るのか

  • エコーサーバ/クライアント
  • エコーサーバは、クライアントから受け取ったデータをそのままクライアントに返す
    • エコー(echo) = こだま
  • サーバは黙っていてもいいのだが、受け取ったデータを自分でも表示する
  • 以下のプログラムは、コピー&ペーストすると、各行のはじめに余分のスペースが入るので、Python の性質上、エラーになります。
  • その他にも、コピペすると改行コードが違うので、、、w

UNIXドメイン エコーサーバ

  • unixSocketServer.py:
       #!/usr/bin/env python
       # UNIX domain Echo server
       import socket
       import os
    
       PIPE = '/tmp/socket54321'
       s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
       s.bind(PIPE)
       s.listen(1)
       conn, addr = s.accept()
       print 'Connected.'
       while True:
           data = conn.recv(1024)
           if not data:
               break
           print 'Echoing:', data
           conn.send(data)
       print 'Closing.'
       conn.close()
       os.unlink(PIPE)
    

UNIXドメイン エコークライアント

  • unixSocketClient.py:
       #!/usr/bin/env python
       # UNIX domain Echo client
       import socket
    
       PIPE = '/tmp/socket54321'
       s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
       print 'Connecting %s.' % repr(PIPE)
       s.connect(PIPE)
       try:
           while True:
               t = raw_input('> ')
               s.send(t)
               data = s.recv(1024)
               print 'Received:', data
       except (EOFError, KeyboardInterrupt):
           pass
       print 'Closing.'
       s.close()
    

実行権を与える

  • ...:
       $ chmod +x unixSocketServer.py
       $ chmod +x unixSocketClient.py
    

動かしてみる

  • ターミナルを二つ
  • ./unixSocketServer.py
  • ./unixSocketClient.py
  • > に対して、キーボードから入力 ... サーバ側で Echoing が表示され、クライアント側に Received 表示
  • クライアント => サーバ => クライアント とデータが渡されている。
  • > に CTRL-C で終了
  • unixSocketServer.py が異常終了すると /tmp/socket54321 が残るので、rm してから

INETドメイン サーバ

  • ipSocketServer.py:
       #!/usr/bin/env python
       # INET domain Echo server
       import socket
    
       HOST = '0.0.0.0'
       PORT = 54321
       s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
       s.bind((HOST, PORT))
       s.listen(1)
       conn, addr = s.accept()
       print 'Connected by', addr
       while True:
           data = conn.recv(1024)
           if not data:
               break
           print 'Echoing:', data
           conn.send(data)
       print 'Closing.'
       conn.close()
    

INETドメイン クライアント

  • ipSocketClient.py:
       #!/usr/bin/env python
       # INET domain Echo client
       import socket
    
       HOST = '127.0.0.1'
       PORT = 54321
       s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
       print 'Connecting %s.' % repr((HOST, PORT))
       s.connect((HOST, PORT))
       try:
           while True:
               t = raw_input('> ')
               s.send(t)
               data = s.recv(1024)
               print 'Received:', data
       except (EOFError, KeyboardInterrupt):
           pass
       print 'Closing.'
       s.close()
    

INET ドメイン版も

  • サーバーとクライアントを UNIX ドメイン版と同様に動かしてみる
  • 補足: ipSocketServer.py で HOST=0.0.0.0 は、使用している全てのIPアドレスについてという意味
  • HOST=127.0.0.1 とすれば、自ホストからの接続のみ受け付ける (UNIX domain と同じ)

隣同士で実験

  • 一人がサーバを動かし、ifconfig で出てくる自分の IPアドレスを隣に伝える
  • もう一人は、クライアントプログラムの IPアドレスの部分を書き換え、隣のサーバに接続できるか試してみる。
  • 接続後、エコーができることを確認する

telnet コマンド

  • 実は、TCP 一般のクライアントとしては、telnet コマンドがある。
  • 1つのターミナルで ipSocketServer.py を動かしておいて、
  • もうひとつのターミナルで telnet 127.0.0.1 54321 を実行してみよう。
  • telnet の切断には ^] ( コントロール+ ] ) を入力して telnet> プロンプトを出し、quit を入れる。

netstat コマンド

  • さらに別のターミナルで netstat -a | grep 54321 と入れてみると、54321 番ポートの状態がわかる。
  • サーバーを起動した直後、クライアントと交信中などに、netstat の結果がどのように変わるか調べてみよう。
  • UNIXドメインのプロセス間通信の状態も表示できるので、UNIX/INET どちらも試してみよう。

レポート

  • 隣同士で実験したときの記録と共に、実験についての考察を書いて、メールで報告 してください。