11

接続ごとに新しいスレッドを開くスレッド化されたPythonソケットサーバーがあります。

スレッドは、質問と回答に基づく非常に単純なコミュニケーションです。基本的に、クライアントは最初のデータ送信を送信します。サーバーは、送信に対して処理を行う外部アプリを実行し、サーバーが返信する応答を返します。クライアントが切断されるまで、ループが再開されます。

クライアントが携帯電話を使用しているため、接続が不安定になり、開いているスレッドが接続されなくなり、ループがrecvで始まるため、この方法で接続が失われた場合に切断するのはかなり困難です。

接続がまだ有効かどうかをテストするために、recvの前に送信を追加することを考えていましたが、クライアントが5秒ごとにのみデータストリームを送信するため、フェイルセーフ送信後にクライアントが切断した場合、これはまったく役に立たない可能性があります。

私は、recvが時々壊れることに気づきましたが、常にではありません。そのような場合、リソースを使用しているゾンビスレッドが残ります。

また、これは私のシステムがDOS化されるための確かな脆弱性である可能性があります。私は木曜日からこれのために何かを見つけようとしてPythonマニュアルとGoogledを調べましたが、私が見つけたほとんどのものはクライアントと非ブロッキングモードに関連しています。

誰かが私をこの問題を解決するための良い方法に向けて正しい方向に向けることができますか?

コードサンプル:

リスナー:

serversocket = socket(AF_INET, SOCK_STREAM)
serversocket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
serversocket.bind(addr)
serversocket.listen(2)
logg("Binded to port: " + str(port))

# Listening Loop
while 1:
  clientsocket, clientaddr = serversocket.accept()
  threading.Thread(target=handler, args=(clientsocket, clientaddr,port,)).start()

# This is useless as it will never get here
serversocket.close()

ハンドラ:

  # Socket connection handler (Threaded)
  def handler(clientsocket, clientaddr, port):
    clientsocket.settimeout(15)

    # Loop till client closes connection or connection drops
    while 1:
      stream = ''
      while 1:
        ending = stream[-6:] # get stream ending
        if ending == '.$$$$.':
          break

        try:
          data = clientsocket.recv(1)
        except:
          sys.exit()

        if not data:
          sys.exit()
          # this is the usual point where thread is closed when a client closes connection normally

        stream += data

      # Clear the line ending
      stream = base64.b64encode(stream[:-6])

      # Send data to be processed
      re = getreply(stream)

      # Send response to client
      try:
        clientsocket.send(re + str('.$$$$.'))
      except:
        sys.exit()

ご覧のとおり、接続に失敗した場合に少なくとも1つは終了をトリガーする必要がありますが、そうでない場合もある3つの条件があります。

4

2 に答える 2

2

threaded申し訳ありませんが、この場合のアイデアは良くないと思います。これらのスレッド(ワーカー?)で多くの処理/実行を行う必要がなく、ほとんどの場合、これらのスレッドはソケットを待機しているため(ブロッキング操作ですか?)、イベントについて読むことをお勧めします駆動型プログラミング。ソケットによると、このパターンは非常に便利です。1つのスレッドですべてのことを実行できるからです。一度に1つのソケットと通信していますが、残りの接続はデータを待機しているだけなので、ほとんど損失はありません。数バイトを送信するときは、別の接続での伝送が必要かどうかを確認するだけです。selectepollについて読むことができます。

Pythonには、これをうまく操作するためのライブラリがいくつかあります。

私はいくつかのプロジェクトで竜巻を使用しました、そしてそれはこの仕事をとてもうまくやります。Libevも素晴らしいですが、cラッパーなので、少しですlow-level(ただし、一部のタスクには非常に適しています)。

于 2012-11-22T00:02:55.047 に答える
0

したがって、提案されたコメントの1つと同様に使用socket.settimeout(float)する必要があります。clientsocket

違いが見られない理由は、呼び出しsocket.recv(bufsize[, flags])てタイムアウトがなくなると、socket.timeout例外がスローされ、その例外をキャッチして終了するためです。

try:
      data = clientsocket.recv(1)
except:
      sys.exit()

次のようなものにする必要があります:

try:
      data = clientsocket.recv(1)
except timeout:
      #timeout occurred
      #handle it
      clientsocket.close()
      sys.exit()
于 2012-10-17T13:07:40.837 に答える