3

usocketのFAQでは、a から読み取って結果socket-streamを確認する方法が推奨されています。end-of-fileこれは、ソケットごとにアクティブなスレッドが 1 つある場合には機能しますが、同じスレッドで複数のソケットにサービスを提供しようとしている場合には満足できないようです。

次のようなものを検討してください

(defparameter *socket* (socket-listen "127.0.0.1" 123456))
(defparameter *client-connections*
   (list (socket-accept *socket*)
         (socket-accept *socket*)
         (socket-accept *socket*)
         (socket-accept *socket*)))

この演習では、実際に 4 つのクライアントが接続していると仮定します。1つのスレッドからそれらを提供する方法は次のようなものです

(wait-for-input *client-connections*)
(loop for sock in *client-connections*
      for stream = (socket-stream sock)
      when (listen stream)
        do (let ((line (read-line stream nil :eof)))
              (if (eq line :eof)
                  (progn (delete sock *client-connections*)
                         (socket-close sock))
                  (handle sock line))))

ただし、切断されたソケットは引き続き に戻りnil、メッセージのないアクティブなソケットからlistenの試みはブロックされますが、他のソケットにメッセージの準備ができていない場合でも、ミックス内に閉じられたソケットある場合はすぐに戻ります。 (ただし、どのソケットが返されたかを特定できないようです)。read wait-for-intput

しばらくクライアントが発言しておらず、3 番目のクライアントが切断された状況では、それを見つけてその特定のソケット接続を閉じる良い方法はないようです。read入力がないブロックであるため、最初の 2 つのクライアントが両方ともメッセージを送信するまでスレッドが待機することを除いて、それらを順番に読み取る必要があります。

私が念頭に置いているが、いくつかの決定的なグーグル検索の後に見つけられなかった解決策は、次のとおりです(好みの降順):

  1. ターゲットのストリームの読み取りがマーカーlistenを返す場合、それ以外の場合はそれと同等の関数が返されます。(上記をこの概念的な関数に置き換えると、残りの部分は書かれたとおりに機能します)tend-of-filelisten
  2. それ以外の場合はそれと同等の関数wait-for-inputは、トリップの原因となった閉じられたソケットのリストを返します。(この場合、閉じたソケットのリストを反復処理し、提案されたread手法でそれらが実際に閉じられていることを確認し、必要に応じて閉じたりポップしたりできます)
  3. それ以外は同等の関数wait-for-inputは、トリップの原因となった最初に閉じられたソケットを返します。(#2と同様ですが、反復ごとに非アクティブな接続を最大1つプルーニングするため、遅くなります)
  4. 各ソケット接続から入力を受信して​​からの経過時間を追跡し、一定期間非アクティブになった後は関係なくそれらを閉じます。(とにかくやりたいと思うかもしれませんが、これだけを行うと、必要以上に多くの切断された接続が保持される可能性があります)
  5. read-charインスタント タイムアウトでストリームからt取得しよう:eofとする関数。(自明ではないが致命的な方法で簡単に破れるように思われるため、これは最後の手段です)unread-charnil

また、これについて正確に間違った方法で考えている場合は、それも指摘してください。

4

1 に答える 1

3

上記のオプション2として私が言及したことが存在することがわかりました。

wait-for-inputconsデフォルトでは、メモリ管理の目的で追跡された接続の完全なリストが返されます(誰かが結果の新しいリストを作成することについて非常に心配していたと報告されています)が、&key何か言いたいことがある接続を返すように指示するパラメーターがあります。

(wait-for-input (list conn1 conn2 conn3 conn4) :ready-only t)

私がそこで探していたものです。これにより、シグナルを送信する接続だけでなく、準備ができているすべての接続が返されるend-of-fileため、ループは両方のケースを処理する必要があります。何かのようなもの

(loop for sock in (wait-for-input *client-connections* :ready-only t)
      for stream = (socket-stream sock)
      do (let ((line (read-line stream nil :eof)))
            (if (eq line :eof)
                (progn (delete sock *client-connections*)
                       (socket-close sock))
                (handle sock line))))

うまくいくはずです。

于 2012-07-22T07:38:30.623 に答える