Pythonのネットワークプログラミング(ソケット)

、ソケット紹介

  • ソケットソケットは、Pythonの標準ライブラリはsocket.py、非常に低レベルのインタフェースライブラリを提供します
  • ソケットは、汎用ネットワーク・プログラミング・インターフェースであり、ネットワークレベルは、1対1の関係ではありません

1、ソケットタイプ

  •  SOCK_STREAM:ストリーム指向のソケット接続、デフォルト値、TCPプロトコル
  •  SOCK_DGRAM:5つの接続されているデータグラムソケット、UDPプロトコル

二、TCPのプログラミング

  • ソケットプログラミングは、両端で、一般的には、サーバー、クライアント、サーバーが断絶と呼ばれ、クライアントと呼ばれるlientを必要とします

1、TCPサーバ

 サーバー側のプログラミングステップ:

  •  Socketオブジェクトを作成します。
  •  IPアドレスとポートポートのアドレスは、バインド()メソッドは、IPv4アドレスがタプルである(「IPアドレスの文字列」、ポート)
  •  リスニングを開始し、指定したIPポートをリッスンし、聞く()メソッド
  •  データを送信するためのSocketオブジェクトを取得します。socket.accept() - >(ソケットオブジェクト、アドレス情報)
  •  接続タプルを確立するために、クライアントが新しいSocketオブジェクトとクライアントのアドレスを返すのを待っているブロックされた方法を受け入れます
  •  アドレスは、それがタプル(CLIENTADDR、ポート)で、IPv4のリモートクライアントのアドレスです
S = socket.socket()#ソケットオブジェクトを作成します
    s.bind(( '127.0.0.1'、8888 ))# タプル
    s.listen()#はリスニング始まる

    #は、接続開い
    S1、情報= s.acceptを( )#クライアント接続が成功し、リターンアドレスとクライアントソケットオブジェクトまでブロック

    データ取得するために使用される#バッファ
    のデータを= s1.recv(1024 
    印刷(データ、情報)
    s1.send(b'magedu.com ACK「)

2、グループチャットプログラムを書きます

CSは、チャットプログラムで、Cすべてのクライアントは、Sがサーバで、サーバが機能を持っている必要があります。

  •   バインドされたアドレスとポートを含むサービスを、開始、モニター
  •   接続を確立し、接続が確立され、複数のクライアントすることができ、異なるユーザが情報を受信します
  •   配布は、ユーザーが接続しているすべてのクライアントに転送されたメッセージを受信します
  •   サービス、レコードのクライアント接続を停止し、サーバーはクラスに対応している必要があります
例としては、
    インポートログを
    インポートソケット
    インポートスレッディング インポート日時
 FORAMTを= '%(いるasctime)のS%(スレッド)のD%(メッセージ)S' logging.basicConfig(レベル= logging.info、フォーマット= FORAMT)クラスChatSever:DEF __init __(自己、 IP = '127.0.0.1'、ポート= 8888):#1 =が起動し、サービスself.sockのsocket.socket()self.addr = (IP、ポート)self.clients = {} =#クライアントself.eventのthreading.Event ()デフを開始(自己): #が起動リスニングself.sock.bind(self.addr)self.sock.listen()#モニタ#accept「(ので、新しいスレッドの印刷を開くには、メインスレッドをブロックします---- -------- " )threading.Thread(対象=のDEF受け入れself.accept).start()(自己):#人接続靴下、クライアント= self.sock.accept()#の閉塞の印刷(111、靴下、クライアント)self.clients [クライアント ] =靴下#のクライアントに追加する#辞書は、RECVは新しいスレッドthreading.Thread開いて、ブロックされたデータを受信する準備ができている(対象= self.recv、引数の=を(私たちの靴下、クライアント) ).start()DEF RECV(自己 、靴下:ソケット、クライアント):# クライアントデータを受信していない間のself.event.is_set():着信MSGをブロックデータ#にデータ= sock.recv(1024)=「{。 Y%/%のM /%のD%のH:%のM:%のS} {}:{} \ {N-} \ N - 」フォーマット(datetime.datetime.now()、* クライアント、data.decode())印刷( 'MSG' のためのSでlogging.info(MSG)self.clients.values():s.send(msg.encode())DEFを停止(セルフ):のストップサービスに#S self.clients.values( ):S。CLOSE()self.sock.close()self.event.set()CS = ChatSever()cs.start()= E threading.Eventは()(しばらくe.waitなし1。 ):CMD = INPUT ( '>>>' ).strip()cmdは== "終了" IF :cs.stop()E.(3待つ)休憩をクライアントは、サーバによって引き起こされる問題は、クライアントが切断された場合、顧客場合、サーバは、クライアントはサーバがしかし切断され知らせるために特別なメッセージを開発し、それは良い習慣です知らない、自分自身を切断する際に知っている割り込みイニシアチブは、クライアントが切断さ、それを使用するという保証はありません、タイムアウトは、クライアントが切断コマンドを提供しても、例外とクリーンアップ接続をキャッチし、例外を返し、サーバは空白のメッセージを送信し、終了を呼び出しますが、まだ終了を増やしたいです機能
以下は、機能を追加するためのコードである
    クライアントを高めるためには、注文から出
    マルチクライアントサポート高めるために


    インポートのログ
    のインポートソケット
    インポートスレッディング インポート日時
 FORAMT =「%(関数は、asctime)S%(スレッド)のD%(メッセージ)S」logging.basicConfig(レベルロギングを=を。 INFO、フォーマット= FORAMT)クラスChatSever:DEF __init __(自己、IP = '127.0.0.1'、ポート= 8888):#1 =が起動し、サービスself.sockのsocket.socket()self.addr = (IP、ポート)セルフ。クライアント= {}#=クライアントself.event threading.Event()は、DEF(自己)開始:#はリスニングを開始self.sock.bind(self.addr)self.sock.listen()#はメインスレッドモニタ#acceptをブロックしますので、新しいスレッドを印刷(「------------」を開け)threading.Thread(ターゲットを=self.accept).start()デフ(受け入れる )自己:#1 人が靴下を接続し、クライアント= self.sock.accept()#ブロックを印刷(111 、私たちの靴下、クライアント)self.clientsは、[クライアント]#=は、私たちの靴下に追加#クライアント辞書は、新しいスレッドthreading.Thread(対象= self.recv、引数=開く、RECVがブロックされ、データを受信する準備ができている。(私たちの靴下、クライアント))スタート()DEFのRECV(:ソケット、クライアントの自己、私たちの靴下を) :#クライアントデータしばらくの受信していないself.event.is_setを():データはMSGの到着するまでブロックされたデータ= sock.recv(1024)#= MSG場合data.decodeは()ストリップ()#クライアントが終了するには、「==コマンド。終了" :self.clients.pop(クライアント)()logging.infoをsock.close(" {}終了" .format(クライアント))BREAK {MSG =":Y%/%のM /%のD%のH:%Mを:%} {S}:{} \ {N-} \ N - 」フォーマット(datetime.datetime.now()、*。クライアント、data.decode())プリント( 'MSG' )logging.info(MSG)のためのS中)(self.clients.values:s.send(msg.encode())DEFを停止(セルフ):中のSのための#ストップサービスself.clients.values():S。CLOSE()self.sock.close()self.event.set()CS = ChatSever()cs.start()E = threading.Event()e.waitないが( 1 ):CMD =入力( '>>>' CMD == "終了"場合).strip():cs.stop()e.wait(3 )ブレーク

3、他の方法

  •  socket.recv():データを取得し、デフォルトでは、道をブロックしています
  •  socket.recvfrom():データを取得するには、タプルを返します。
  •  )(socket.recv_info:nバイトのデータを取得した後、バッファに格納されています
添付ファイル・オブジェクトに関連付けられたソケット作成する
メイクファイルグループチャット書き換え型の使用


インポートログ
インポートソケット
インポートスレッディング インポート日時
 FORAMT =「%(いるasctime)S%と(スレッド)Dの%(メッセージ)S」logging.basicConfig(レベルlogging.info =、フォーマット= FORAMT)クラスChatSever:DEF __init __(自己、IP = '127.0.0.1'、ポート= 8888):#1 =が起動し、サービスself.sockのsocket.socket()self.addr = (IP、ポート)self.clients = {}#=クライアントself.event threading.Event()DEF開始(自己):#開始リスニングself.sock.bind(self.addr)self.sock.listen()#モニタが#acceptます( '------------'ので、新しいスレッドを印刷を開くには、メインスレッドをブロック)threading.Thread(ターゲット= self.accept).start()は、DEF(自己)受け入れ:#多人数接続されていないながら、self.event.is_set():靴下、クライアント= self.sock.accept()# ブロックを印刷(111 、私たちの靴下、クライアント)F = sock.makefile(MODE = 'RW' )self.clients [クライアント] = Fの# RECVがブロックされている、#クライアントがデータを受信する準備ができている辞書に追加、新しいスレッドthreading.Thread(対象= self.recv、引数=(F、クライアント)、名前= 'RECV'を開く).start()DEFのRECV(自己、F、クライアント):#クライアントのデータを受信していない間のself.event.is_set():試してみる:除くブロックにデータ= f.readline()#改行E AS例外:logging.error(E)任意の#退出例外保証=データは'辞め' MSG = "終了" IF MSGコマンドを== data.strip()#クライアントが終了を:self.clients.pop(クライアント)f.close()logging.infoを( "{}終了します" .format(クライアント))BREAK MSGは= "{:Y%/%M /%D%H:%M:%S} {}:{} \ {N-} \ N-" .format(datetime.datetime.now( )、* クライアント、データ)を印刷( 'MSG'秒間)logging.info(MSG)でself.clients.values():s.wtitelines(MSG)s.flush()defを停止(自己):#停止服务中のためself.clients.values():S。CLOSE()self.sock.close( )self.event.wait(3 )self.event.set()DEF show_thread(E:threading.Event):(3 e.waitないがlogging.info(threading.enumerate(:)))DEF メイン(): E = threading.Event()CS = ChatSever()cs.start()threading.Thread(目標= show_thread、引数=(E)、NAME = 'showthread' ).start()(1 e.waitないが) :CMD =入力( '>>>' ).strip()CMD == "終了"場合:cs.stop()e.wait(3 )ブレークなら__name__ == "__main__" :main()のソケット太底层了、实际开发中很少使用这么底层的接口


三、TCPクライアント

  •  クライアントのプログラミングステップ
  •  Socketオブジェクトを作成します。
  •  接続し、リモートサーバーのIPアドレスとポートに接続します()
  •  データ送信:送信を使用して、データを受信するためのrecv方法
  •  、リソースの解放を接続を閉じます
インポートログを
インポートソケット
インポートスレッディング
インポート日時
 FORAMT = '%(関数は、asctime)S%(スレッド)D%(メッセージ)S'  logging.basicConfig(レベル= logging.info、フォーマット= FORAMT)クラスChatClientを:__init __(自己、IP DEF = '127.0.0.1'、ポート= 8888 ):self.sock = socket.socket()self.addr = (IP、ポート)self.event = threading.Event()self.start()スタートDEF(セルフ): #接続リモートに開始データを受信する準備ができself.sock.connect(self.addr)位、RECVがブロックされ、新しいスレッドthreading.Threadを開く(目標= self._recv、名前= "RECV" ).start( )デフ_recv(自己):#クライアントのデータを受信していない間のself.event.is_set():試してみる:データは= self.sock.recv(1024)#しかブロックEとして例外:logging.error(E)ブレークMSG = "{:%Y /%M /%d個の%のH:%のM:%のS} {}:{} \ N {} \ n" .format(日時。 datetime.now()、* クライアント、データ)logging.info(MSG)DEF (自己、MSGを送信する:STR):データ= "{} \ n" .format(msg.strip())をコード()自己。 sock.send(データ)は、DEF (自己)を停止:logging.info( "{}破壊" .format(self.addr))self.sock.close()self.event.wait(3 )self.event.set( )logging.info( "クライアントが停止" )DEF show_thread(E:threading.Event):(3 e.waitないが)デフlogging.info(threading.enumerate(:)) メイン():E = threading.Eventを( )CC = ChatClient()しばらく真:MSG =入力( '>>>' であればmsg.strip()== "終了" :cs.stop()ブレークcc.send(MSG)__name__ == '__main__'の場合:メイン()

 

四、Socketserver

  • ルーチンプログラミングがありますが、あまりにもソケットプログラミングの基礎となるが、Pythonモジュールパッケージはsocketserverで、ソケットのように多くの言語が基本となるAPIをカプセル化し、堅牢なコードを書きたいすることは非常に困難です
  • エンタープライズクラスの急速な発展を促進するためのネットワークサービスのプログラミングフレームワーク

1継承、クラス

  •  SocketSever書き込みネットワークサーバを簡素化
  •  TCPServerの、UDPServer、UnixStreamServer、UnixDatagramServer:それは4つの同期クラスを持っています
  •  非同期ThreadMixlnをサポートするための2つのForkingMixlnのmixinクラスとクラス

2.プログラミング・インタフェース

  •  socketserver.BaseServer(sever_address、RequestHandleClass)
  •  結合すると、サーバのアドレス情報を提供する必要があり、RequestHandlerClassを処理するための要求、RequestHandleClassクラスは、クラスBaseRequestHandlerのサブクラスでなければなりません

3、BaseRequestHandlerクラス

  •  そして、ユーザベースのユーザ接続要求処理は、ユーザ要求サーバーインスタンスを受信した後、最終的にクラスをインスタンス化し、それが初期化され、三つのパラメータに構成:要求、client_address、サーバー
  •  缶後のクラスBaseRequestHandlerのインスタンスに
  •  self.requestソケット・ターゲット・クライアントが接続されています
  •  自身self.server tcpserverはあります
  •  self.client_addressですクライアントアドレス
  •  これは、サブクラスがオーバーライドすることができ、三つの関数の最初の呼び出しになります
インポートスレッディング
    インポートSocketServerの

    クラス(SocketServer.BaseRequestHandlerの)MyHandlerという:
        DEF ハンドル(自己): プリント(self.server、self.request、self.client_addressです) プリント(「{} handler'.format(セルフclass__である.__ ))印刷(セルフclass__は.__です)印刷(タイプ(セルフ).__ dict__にマジック)印刷(セルフ.__クラス__.__拠点__ [0] .__ dict__にマジック)印刷(threading.enumerate()、threading.current_thread())= ADDR( '127.0.0.1'、8888 )サーバ= 対応socketserver.ThreadingTCPServer(ADDR、MyHandlerという)server.serve_forever(受け入れる ) ハンドラメソッドとソケット、試験結果は、ソケット接続を介してユーザの接続要求が確立され、クライアントのアドレスに格納されているself.requestオブジェクトが生成されますself.client_addressですに保存で

4、サーバーを作成するには、いくつかのステップが必要です

  •  サブクラスはBaseRequestHandlerクラスなければならないと要求処理クラスを作成するために、他のハンドル()メソッドを覆うことにより、この方法は、着信要求を処理します
  •  あなたはそれをサーバのアドレス、および要求ハンドラクラスを渡し、クラスのサーバーをインスタンス化する必要があります
  •  次に、サーバオブジェクトでhandle_request()またはserver_forever()メソッドを呼び出します
  •  コールserver_closeは())(server_foreverを停止待つ、ソケット、シャットダウン()メソッドをクローズ

EchoServerを達成するための5、

  • 名前が示すように、エコーは、どのような情報が返されているものについては、クライアントから送信されたメッセージ何を、どのようなメッセージをエコーし​​ます
輸入スレッド
輸入socketserverの

クラスEchoHandler(socketserver.BaseRequestHandler):
    デフ仕上げ(自己): スーパー()仕上げ()。 self.event.set()#清理工作
 デフセットアップ(自己): スーパー()のセットアップ() 自己。イベント= threading.Event()#初始化工作
 デフ(自己)を扱う:スーパー()(ハンドル)されていないが()self.event.is_set:データ= self.request.recv(1024 ).decode()MSG = " {} {}」.format(self.client_addressです、データ).encode()self.request.send(MSG)プリント( '終了' )ADDR =( '127.0.0.1'、8888 )サーバ=socketserver.ThreadingTCPServer(ADDR、EchoHandler)server_thread = threading.Thread(対象= server.serve_forever、デーモン= 真)server_thread.start()してみてください:ながら真:CMD =入力( '>>>' )cmd.strip場合は() == '終了' :を除くブレーク印刷:電子などの例外を除いて(e)はKeyboardInterrupt:プリント([終了] )最後に:server.shutdown()server.server_close()

 

おすすめ

転載: www.cnblogs.com/jiangzuofenghua/p/11453886.html