3

複数のポート (例: TCP:1234、TCP:5678 など) で実行できる Python ネットワーク アプリケーションを作成したいと考えています。

したがって、それぞれがクライアント接続をリッスンするn個のソケットがあるとしましょう。さまざまなポートをリッスンする単純なネットワーク アプリケーションをプログラムしましたが、アプリケーションを実行すると、最初のソケット プロセスのリッスン フェーズで停止します。

N個のポートをリッスンし、それぞれがクライアントが接続するのを待っているときに、単一のpythonプログラムを作成するにはどうすればよいですか。すべてのソケットが同時に実行され、リッスンしています。

Socket/Process #1: Listening on TCP Port 5000
Socket/Process #2: Listening on TCP Port 5001
Socket/Process #3: Listening on TCP Port 5002
...
Socket/Process #N: Listening on TCP Port 6000

どんなアイデアでも大歓迎です。

#!/usr/bin/env  python

import socket

def getPortList():
    ports=[]
    nPort=int(raw_input("# how many ports you want? "))
    j = 0
    for i in range(0,nPort):
        ports.append(int(raw_input("Enter port number: ")))
        j+=1
    return ports

def myTCPSocket(port=5000):
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR,1)
    s.bind(("", int(port)))
    print ("\nWaiting for connections!\n")
    s.listen(5)
    (clientsock, clientaddr) = s.accept()
    print(clientaddr)

    data = "start"

    while len(data):
                clientsock.send("\nWelcome to Echo Server\n")
                data = clientsock.recv(1024)
                print ("Data sent is: ", data)
                clientsock.send(data)
                if data == "exit\r\n":
                        clientsock.close()

plst = getPortList()

for item in plst:
    myTCPSocket(item)
4

1 に答える 1

2

複数のソケットでリッスンすることは、単一のソケットでリッスンすることとまったく同じです。

リスナーソケットとすべてのクライアント接続ソケットを何らかの方法で処理する必要があります。これは次の方法で実行できます。

  • ループアラウンドselect.select(またはpollkqueueepollなど) を記述します。
  • 標準ライブラリ リアクターの使用asyncore
  • サードパーティのリアクターまたは Twisted のようなプロアクターを使用する。
  • OS 固有の機能を使用する (たとえば、PyObjC を介して Cocoa ランループとサーバーを使用する)。
  • 新しい接続ごとにスレッドを作成します。
  • 新しい接続ごとにサブプロセスを作成します。

これらのスキームのほとんどすべては、複数のリスナーを扱う場合にも機能します。最も簡単な方法は、2 つを 1 つに結合することです (たとえば、selectすべてのリスナーとすべてのクライアント ソケットを処理する単一のループ、またはリスナーとクライアント ソケットごとに別のスレッドを処理する)。

パフォーマンスまたはデバッグ上の理由から、代わりに 2 層のハイブリッド アプローチを使用することをお勧めします (たとえば、各リスナーに 1 つのスレッド、それぞれselectにすべてのクライアント ソケットのループがあるか、各リスナーに 1 つのプロセス、それぞれに 1 つのスレッドがある)。各クライアントソケット)。ただし、それを行う正当な理由がない場合は、複雑さを加えないでください。

http://pastebin.com/QebZMKz3は、単純な単一select実装を示しています。出力は次のとおりです。

$ ./multiserve.py 22222 22223 &
(('127.0.0.1', 22222), ' listening')
(('127.0.0.1', 22223), ' listening')
$ echo 'abc' | nc localhost 22222
(('127.0.0.1', 22222), ' <- ', ('127.0.0.1', 64633))
(('127.0.0.1', 64633), ' <- ', 'abc\n')
(('127.0.0.1', 64633), ' EOF')

2 つの同時クライアントを実際に処理する必要がないと思われる場合は、おそらく間違っていますが、上記の手法のほとんどを使用でき、わずかに単純になる可能性があります。たとえば、リスナーを選択してから、ループに戻る前に、受け入れとクライアントとソケットの通信を同期的に行うことができます。または、リスナーごとにプロセスまたはスレッドを作成し、accept と client-socket 通信をそれぞれの中で同期的に処理することもできます。等々。

http://pastebin.com/wLVLT49iは、あなたがしようとしていたと思われる簡単な例を示しています。ソケットごとに ( 経由でos.fork) プロセスを使用するため、異なるポートでの同時接続が可能です。各プロセス内で非同期に何もしないため、同じポートへの同時接続は許可されません。(そしてもちろん、それは を使用するため、POSIX 固有forkです。)

最初に非同期ネットワーク サーバーの作成方法を学びたい場合はselect、スレッドとスレッドの 2 つの異なる実装を行うことをお勧めします。それらは概念的に基本的であり、コーディングが比較的簡単です。

まず、 についてselectは、イベント ループの概念を理解する必要があります。イベントとは、新しい着信接続ごと、既存の接続の着信ネットワーク パケットごと、書き込み先のパイプの詰まりが解消されるたびに発生します。ここで注意が必要なのは、他のイベント ループと同様に、各イベントを処理し、ブロックせずに、CPU 時間をあまり消費せずに返す必要があることです。たとえば、エコー サーバーの場合、一部のソケットがビジーである可能性があるため、他のソケットに書き込みを行うことはできません。代わりに、各ソケットの書き込みバッファに出力を固定する必要があり、準備が整ったときにイベントループを実行して後で取得します。

一方、スレッドの場合は、接続ごとに個別のスレッドを使用すると、すべてが簡単になるように見えますが、あるスレッドから別のスレッドにメッセージをエコーする必要がある場合はどうなるでしょうか? 何らかの形式のスレッド間通信、またはスレッド間同期による共有データが必要です。したがって、Queue各ソケットに for writes がある可能性があるため、他のソケットのスレッドはメッセージをキューにプッシュできます。

これらはどちらも、よく回されたリアクターまたはプロアクターができることほど優れたものではありませんが、基本を学ぶ価値があります。特に、ブロックの問題 (からselect) と通信の問題 (スレッドから) の両方に直面することになるためです。 )どのソリューションでも、より高いレベルで作業している場合、それらははるかに不可解でデバッグが困難になります。

于 2012-10-29T22:07:41.127 に答える