Pythonの基本的なsocketプログラミングの実戦攻略

7143 ワード

ネットワーク通信において、socketはほとんどどこにでもあり、アプリケーション層とTCP/IPプロトコルクラスタが通信する中間ソフトウェア抽象層と見なすことができ、2つのアプリケーションが互いに通信するインターフェースであり、複雑なTCP/IPプロトコルの詳細はインターフェースの後に隠されている。Pythonはsocketモジュールを提供しています。とても便利にsocketプログラミングができます。
server socketを作成します。
socket法を使って新しいsocketを作成します。通常は二つのパラメータを提供します。一番目のパラメータはaddress familyで、二つ目はsocket typeです。

#create an INET, STREAMing socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
以上、address familyをIPプロトコルとして作成し、転送プロトコルはTCPのsocketである。
サーバー側はsocketを作成した後、IPアドレスとポートに結びつけてサービスを提供する必要があります。これはbindメソッドを使用します。

# bind the socket to all available interfaces on port 8888
s.bind(('', 8888))
listenメソッドを使用して、socketを傍受状態に設定します。listen方法は、一番多くのキューで受信できる要求数を示すパラメータの後に続く。

#become a server socket
serversocket.listen(5)
今はもうserver socketを作成しました。無限の循環体を作成して、クライアントからの接続を受信し、accept方法を利用して、新しいsocketに戻ります。リモートとの接続を表しながらアドレスペアを返します。リモート接続のIPアドレスとポート番号を表します。

# enter the main loop of the web server
while 1:
  #accept connections from outside, return a pair (conn, addr)
  (clientsocket, address) = serversocket.accept()
  #now do something with the clientsocket
  #in this case, we'll pretend this is a threaded server
  ct = client_thread(clientsocket)
  ct.run()
通常、循環体の中のserver socketは、任意のデータを送信したり、受信したりしません。遠端からの接続だけを受信して、新しい接続を他のスレッドに渡して処理して、他の接続を継続して聞きます。そうでないと、接続を処理する時、他の新しい接続を受け入れることができなくなります。
次に、新しいスレッドを作って、接続を処理します。まず、recv法を使って、socketからのデータを受け取ります。後に一つのパラメータを持って、一回で最大許容できるデータの大きさを表します。そして、sendallメソッドを使って、socketに返信し、sendallは全てのデータの送信が完了するか、または異常が発生するまでデータを送り続けます。最後に、socketを閉じてください。各socketはシステムの中の一つのファイル記述子を表していますので、即時にクローズしていないと、システムの最大のファイル記述子の数を超えるかもしれません。新しいsocketを作成することができません。

def handle_request(sock, addr):
  print "Accept new connection from {addr}".format(addr = addr)
  request_data = client_connection.recv(1024)
  print request_data.decode()
  http_response = "Hello, world!"
  # send response data to the socket
  sock.sendall(http_response)
  sock.close()
server socketをまとめるには主に以下のいくつかのステップがあります。
  • 新しいserver socketを作成します。
  • は、socketをアドレスとポートに結びつける。
  • は遠隔からの接続をヒアリングする。
  • は、接続を受け取り、他のスレッド処理に配信する。
  • 以下は完全なserver socketの例コードです。
    
    import socket
    import threading
    
    SERVER_ADDRESS = (HOST, PORT) = '', 8888
    REQUEST_QUEUE_SIZE = 1024
    
    def handle_request(sock, addr):
      print "Accept new connection from {addr}".format(addr = addr)
      request_data = client_connection.recv(1024)
      print request_data.decode()
      http_response = "Hello, world!"
      # send response data to the socket
      sock.sendall(http_response)
      sock.close()
    
    def serve_forever():
      server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
      # reuse socket immediately
      server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
      server_socket.bind(SERVER_ADDRESS)
      server_socket.listen(REQUEST_QUEUE_SIZE)
      print 'Serving HTTP on port {port} ...'.format(port = PORT)
    
      while True:
        try:
          client_connection, client_address = server_socket.accept()
        except IOError as e:
          code, msg = e.args
          # restart 'accept' if it was interrupted
          if code == errno.EINTR:
            continue
          else:
            raise
        # create a thread to handle this request
        t = threading.Thread(target=handle_request, args=(sock, addr))
        t.start()
    
    if __name__ == '__main__':
      serve_forever()
    
    
    client socketを作成します。
    クライアントのsocketは比較的簡単で、主に以下のいくつかのステップを含みます。
  • socketを作成します。
  • はサーバに接続されている。
  • は、サーバにデータを送信する。
  • は、サーバから返されたデータを受信する。
  • socketを閉じます。
  • 
    import socket
    
    HOST = 'localhost' # the remote host
    PORT = 8888 # port used by server
    
    client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # connect to server
    client_socket.connect((HOST, PORT))
    # send something to the server
    client_socket.sendall("Hello, world")
    data = client_socket.recv(1024)
    client_socket.close()
    print 'Received', repr(data)
    
    
    PS:socketモジュール使用の引用
    
    sk = socket.socket(socket.AF_INET,socket.SOCK_STREAM,0)
    
    パラメータ一:アドレスクラスタ
    sockett.AF_INET IPv 4(デフォルト)
    sockett.AF_INET 6 IPv 6
    sockett.AF_UNIXは単一のUnixシステムのプロセス間通信のみに使用できます。
    パラメータ2:タイプ
    sockett.SOCK_STREAM流式socket,for TCP(デフォルト)
    sockett.SOCK_DGRAMデータ报式socket,for UDP
    sockett.SOCK_RAWのオリジナルソケットは、普通のソケットではICMP、IGMPなどのネットワークレポートは処理できません。SOCK_RAWでいいです次に、SOCK_RAWはまた、特別なIPv 4報文を処理することができる。また、元のソケットを利用して、IP_を通すことができます。HRINCLソケットオプションはユーザーがIPヘッダを構成する。
    sockett.SOCK_RDMは信頼できるUDP形式であり、つまりデータ・グラムを配信することを保証するが、順序は保証されていない。SOCK_RAMは、元のプロトコルに対する低レベルのアクセスを提供するために使用され、ICMP報文の送信など、特定の特殊な動作を実行する必要があるときに使用される。SOCK_RAMは、通常、上位ユーザまたは管理者が実行するプログラム使用に限定される。
    sockett.SOCK_SEQPACKET信頼できる連続パケットサービス
    パラメータ三:プロトコル
    0(デフォルト)特定のアドレス家族に関するプロトコルです。0であれば、システムはアドレスフォーマットと接続カテゴリに従って、自動的に適切なプロトコルを選択します。
    sk.bind(address)
    s.bind(address)はソケットをアドレスにバインドします。addressアドレスのフォーマットはアドレス族によって決まります。AFで_INETでは、タプル(host,port)としてアドレスを表します。
    sk.listen(backlog)
    着信接続の監視を開始します。バックロゴは接続を拒否する前に最大接続数を指定します。
          backlogsは5に等しい。カーネルは接続要求を受けたが、サーバがまだacceptを呼び出していないので、処理する接続個数は最大5です。
          この値は無限大にはできません。カーネルの中で接続待ち行列を維持するためです。
    sk.set blocking(book)
    ブロッキングするかどうか(デフォルトTrue)、Falseを設定すると、acceptとrecvのデータがないとエラーが発生します。
    sk.accept()
    接続を受け入れて返します。ここでconnは新しいソケットオブジェクトであり、データを受信して送信するために使用されます。addressはクライアントを接続するアドレスです。
    TCP顧客の接続(ブロック式)を受信し、接続の到来を待つ。
    sk.co nnect(address)
    addressに接続するソケット。一般的に、addressのフォーマットはタプルで、もし接続が間違ったら、socket.errorエラーに戻ります。
    sk.co nnect_ex(address)
    同じですが、戻り値があります。接続に成功した時は0に戻り、接続に失敗した時は符号化に戻ります。例えば、10061
    sk.close()
    ソケットを閉じる
    sk.recv(bufsize[,flags])
    ソケットのデータを受け付けます。データは文字列で返します。最大受信可能な数をbufsizeで指定します。flagsはメッセージに関する他の情報を提供し、通常は無視することができる。
    sk.recvfrom(bufsize[.flags])
    recv()と似ていますが、戻り値は(data,address)です。dataは受信データを含む文字列であり、addressは送信データのソケットアドレスである。
    sk.send(string[,flags])
    stringのデータを接続のソケットに送ります。戻り値は、送信されるバイトの数であり、この数は、stringのバイトサイズより小さいかもしれない。
    sk.sedall(string[,flags])
    stringのデータを接続のソケットに送りますが、戻る前にすべてのデータを送信してみます。成功してNoneに戻ります。失敗したら異常を投げます。
    sk.sendto(string[,flags],address)
    ソケットにデータを送ります。addressは形式がipad,portのタプルで、リモートアドレスを指定します。戻り値は送信バイト数です。この関数は主にUDPプロトコルに使用されます。
    sk.settimeout(timeout)
    ソケット操作の超時期を設定します。timeoutは浮動小数点で、単位は秒です。値はNoneで、時期を超えていないことを表しています。一般的に、超期間はソケットを作成したばかりの時に設定するべきです。接続のための操作が可能です。(例えば、client接続は最大5 sまで待つ)
    sk.getpeername()
        この方法はクライアントでのみ使用でき、server端末の情報を確認するために使用されます。
    ソケットを接続するリモートアドレスを返します。戻り値は通常タプルである。
    sk.get sockname()
        この方法はserver側でserver側の自分の情報を確認することしかできません。
    ソケットの住所を返します。通常はタプルです。
    sk.fileno()
    ソケットのファイル記述子