pythonネットワーククライアント

7269 ワード

pythonネットワークプログラミング-ネットワーククライアント
理解する
SOcketはオペレーティングシステムにおけるI/Oシステムの延長部分であり,プロセスと機器間の通信を提供する.いくつかの態様では、socketは標準的なファイル記述子と見なすことができる.
ソケットの作成
クライアント・プログラムの場合、socketを確立するには2つのステップが必要です.
  • socketオブジェクト
  • を確立する
  • リモートサーバに接続する
  • ソケットオブジェクトを構築する際には、通信タイプとプロトコルファミリーの2つのことをシステムに伝える必要があります.
  • 通信タイプは、データをどのプロトコルで伝送するかを示す.
  • プロトコルファミリー、例えばIPv 4、IPv 6、IPX/SPX(NetWare)、AFP(Appleファイル共有)、主にデータがどのように伝送されるかを定義します.

  • インターネット通信の場合、タイプは基本的にAF_INET(IPv 4)、プロトコルファミリーは一般的にTCP通信のSOCK_STREAMまたはUDP通信のSOCK_DGRAM.
    TCP通信の場合、socket接続が確立され、一般的に次のようなコードが使用されます.
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    socketに接続するには、一般的にリモートホスト名またはIPアドレスとリモートポートを含むtupleを提供する必要があります.ソケットを接続するには、一般的にこのようなコードが使用されます.
    s.connect(("www.example.com",80))
    次のプログラムは接続を確立し、すぐに終了します.使用意義はありませんが、完全な機能を持つ例です.コードは以下の通りです.
    #!/usr/bin/env python
    # Basic Connection Example - connect.py
    
    import socket
    
    print "Creating socket...",
    s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    print "done."
    
    print "Connecting to remote host...",
    s.connect(("www.baidu.com",80))
    print "done."
    

    上の例はwww.baiduに接続する.com上のwebサーバは、ステータス情報を印刷して終了します.
    ポート番号の検索
    ほとんどのオペレーティングシステムには、サーバポート番号のリストが付属しています.pythonのsocketライブラリにはgetservbyname()の関数が含まれており、自動的にクエリーできます.Unixシステムでは、/etc/servicesディレクトリの下でこのリストを見つけることができます.
    このリストをクエリーするには、プロトコル名とポート名の2つのパラメータが必要です.ポート名は文字列です.
    次は、ポート番号ではなくポート名を使用して、前のプログラムの変更です.
    #!/usr/bin/env python 
    # Revised Connection Example - connect2.py
    
    import socket
    
    print "Creating scoket...",
    s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    print "done."
    
    print "Looking up port number...",
    port = socket.getservbyname('http','tcp')
    print "done."
    
    print "Connecting to remote host on port %d..." % port,
    s.connect(("www.baidu.com",port)),
    print "done."
    

    HTTPが80ポートを使用していることを事前に知る必要がないことがわかります.
    ソケットから情報を取得
    SOcket接続が確立されると、いくつかの有用な情報が得られます.次の例では、これらの機能を示します.
    #!/usr/bin/env python
    #Information Example - connect3.py
    
    import socket
    
    print "Creating socket..."
    s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    print "done."
    
    print "Looking up port number...",
    port = socket.getservbyname('http','tcp')
    print "done."
    
    print "Connecting to remote host on port %d..." % port,
    s.connect(("www.baidu.com",port))
    print "done."
    
    print "Connected from ",s.getsockname()
    print "Connected to ",s.getpeername()
    

    このプログラムを実行すると、2つの新しい情報が表示され、1つ目は自分のIPアドレスとポート番号を表示し、2つ目はリモートマシンのIPアドレスとポート番号を表示します.クライアントにとって、ポート番号はオペレーティングシステムによってランダムに割り当てられており(ルールがあるかもしれません)、このプログラムを実行するたびにポート番号が異なることがわかります.
    ソケット通信を利用する
    pythonでは、次の2つの方法があります.
  • socketオブジェクト
  • ファイルクラスオブジェクト
  • socketオブジェクトは、オペレーティングシステムのsend()、sendto()、recv()、recvfrom()呼び出しのインタフェースを提供します.
    ファイルクラスオブジェクトには、read()、write()、readline()などのより典型的なpyhonインタフェースがあります.
    ファイルクラスオブジェクトは、提供されるreadline()関数によってほとんどの解析を自動的に処理できるため、線形プロトコル向けに一般的に使用されます.しかし,ファイルクラスオブジェクトは一般にTCP接続に対してのみ良好に動作し,UDPに対してはかえって良好ではない.TCP接続の動作は標準的なファイルと似ているため、データ受信の正確性を保証し、ファイルと同様にバイトストリーム形式である.UDPはファイルのようにバイトストリーム形式で伝送されるのではなく,パケットベースの通信である.ファイルクラスオブジェクトは各基本パケットを操作することができないので,UDPパケットの送信と受信の基本メカニズムを確立することはできず,同時にエラーチェックも困難である.
    エラー処理
    ネットワークにエラーが発生すると、socketコードに異常が発生します.特定のエラーフィードバックは、特定のアプリケーションによって異なります.たとえば、ダウンロード中に通信が中断した場合、そのポイントでダウンロードを再開しようとします.
    ソケット異常
    異なるネットワーク呼び出しによって異なる例外が発生します.次の例では、socketオブジェクトを処理するときに、通常の例外をどのようにキャプチャするかを示します.この例では、接続するホスト名、サーバのポート番号、または名前の3つのコマンドラインパラメータが必要です.サーバからダウンロードしたいファイルです.プログラムはサーバに接続し,特定のファイルに対して簡単なHTTP要求を送信し,同時に結果を表示する.プロセス全体で、さまざまなタイプの潜在的なエラーを処理しようとします.
    #!/usr/bin/env python 
    # Error Handling Example - socketerrors.py
    
    import socket,sys
    #          
    host = sys.argv[1] #   
    textport = sys.argv[2] #   
    filename = sys.argv[3] #      
    
    try:
        s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    except socket.error,e:
        print "Strange  error creating scoket: %s" %e
        sys.exit(1)
    
    # Try parsing it as a numeric port number.
    
    try:
        port = int(textport)
    except ValueError:
        # That didn't work,so it's probably a protocol name.
        # Look it up instead.
        try:
            port = socket.getservbyname(textport,'tcp')
        except socket.error,e:
            print "Couldn't find your port:%s" %e
            sys.exit(1)
    try:
        s.connect((host,port))
    except socket.gaierror,e:
        print "Address-related error connecting to server: %s" %e
        sys.exit(1)
    except socket.error,e:
        print "Connecting error:%s" %e
        sys.exit(1)
    
    try:
        s.sendall("GET %s HTTP/1.0\r
    \r
    " %filename) except socket.error,e: print "Error sending data:%s" %e sys.exit(1) while 1: try: buf = s.recv(2048) except socket.error,e: print "Error receving data:%s" %e sys.exit(1) if not len(buf): break sys.stdout.write(buf)

    このプログラムでは,異常処理は単純に友好的な情報を印刷して実行を終了するだけである.
    pythonのsocketモジュールでは、実際には4つの可能な例外が定義されています.
  • 一般I/Oと通信問題に関するsocket.error;
  • クエリーアドレスsocket.gaierror;
  • 他のアドレスエラーに関するsocket.herror;
  • 処理タイムアウトに関するsocket.timeout;

  • 欠落したエラー
    上のプログラムでエラー処理に問題があります.通信処理に問題がある場合がありますが、オペレーティングシステムからエラーが返されていないため、異常は発生しません.
    クライアント接続とサーバ書き込みクライアント要求の間、リモートサーバが接続を切断すると、このような問題が発生します.上記のプログラムからrecv()の呼び出しではデータが受信されず、プログラムは正常に終了します.
    多くのオペレーティングシステムでは、ネットワーク上でデータを送信する呼び出しが、リモート・サーバが情報を受信したことを確認する前に返される場合があります.したがって、sendall()に対して正常に呼び出されたデータから、実際には受信されない可能性が高い.
    この問題を解決するには、書き込み操作が終了すると、shutdown()関数をすぐに呼び出す必要があります.
    一部のプロトコルでは、開始時には1回以上書き込み操作が行われず、書き込みのたびにshutdown()が呼び出されるのは現実的ではありません.最後に書いた後、実行する必要があります.これにより、すべての書き込み操作がこの点で成功することが保証されます.
    ファイルクラスオブジェクトによるエラー
    makefile()関数を使用してsocketからファイルクラスオブジェクトを得ることができます.実際、このファイルクラスオブジェクトは実際のsocketを呼び出すので、ファイルクラスオブジェクトによって発生する異常はsocket自身のsend()とrecv()関数と同じです.
    UDPの使用
    UDP通信ではファイルクラスオブジェクトはほとんど適用されません.以下に、基本的なUDPクライアントの例を示します.
    #!/usr/bin/env pyhton 
    # UDP Example -udp.py
    import socket,sys
    
    host = sys.argv[1]
    textport = sys.argv[2]
    
    s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
    try:
        port = int(textport)
    except ValueError:
        port = socket.getservbyname(textport,'udp')
    
    s.connect((host,port))
    print "Enter data to transmit:"
    data = sys.stdin.readline().strip()
    s.sendall(data)
    print "Looking for replies;press Ctrl-C or Ctrl-Break to stop." 
    while 1:
        buf = s.recv(2048)
        if not len(buf):
            break
        sys.stdout.write(buf)
    

    上記の例では、2つのコマンドラインパラメータが必要です.1つのホスト名と1つのサーバポート番号です.サーバに接続され、送信するテキストの行を入力するよう求められます.データが送信された後、返信を待つために無線サイクルに入り、Ctrl-CまたはCtrl-Breakでプログラムを終了することができる.
    まとめ
    ネットワーク通信の基本インタフェースはsocketであり、オペレーティングシステムの基本I/Oからネットワーク通信を拡張している.socketはsocket()関数で確立され、connect()関数で接続されます.SOcketがローカルとリモートのipアドレスとポート番号を決定できることを得た.socketは、異なるプロトコルにとって、tcpおよびudp通信を処理できる汎用インタフェースである.
    リモート通信では多くのエラーが発生する可能性がありますが、すべてのエラーチェックが重要です.異常がすぐに現れない場合が多いので、shutdown()を使用して、書き込みエラーが発生するたびに注意できるようにします.
    pythonは、UDPおよび高度なTCP目的のための標準socketインタフェースと、単純なTCP通信のためのファイルクラスインタフェースの2つのsocket動作インタフェースを提供する.