状況の簡単な概要:ストリームがクライアントによって閉じられているかどうかを検出できますか?
私は情報を受け取り、ソケット上で回答を送信するサービスを提供しています。接続は保護されていません。これらの接続にTLSを提供できる別のサービスをセットアップしたいと思います。この新しいサービスは単一のポートを提供し、提供されたクライアント証明書に基づいて接続を分散します。私はいくつかの理由でstunnelを使いたくはありません.1つは、受信ポートごとに1つの転送ポートが必要なことです。
私は現在、実装しようとしているソリューション:
を基本的には、私はカップルにNetworkStreamとSslStream(受信)(送信しようとしている - かもしれないソケットを、私はにそれを置きます着信と一致するようにNetworkStreamを作成し、2つのリンクを読み書きします。このリンクは、クライアント(SSL/TLSを介して)とサービス(セキュリティ保護されていない接続を介して)との間のフローを提供します。
public class StreamConnector
{
public StreamConnector(Stream s1, Stream s2)
{
StreamConnectorState state1 = new StreamConnectorState(s1, s2);
StreamConnectorState state2 = new StreamConnectorState(s2, s1);
s1.BeginRead(state1.Buffer, 0, state1.Buffer.Length, new AsyncCallback(ReadCallback), state1);
s2.BeginRead(state2.Buffer, 0, state2.Buffer.Length, new AsyncCallback(ReadCallback), state2);
}
private void ReadCallback(IAsyncResult result)
{
// Get state object.
StreamConnectorState state = (StreamConnectorState)result.AsyncState;
// Finish reading data.
int length = state.InStream.EndRead(result);
// Write data.
state.OutStream.Write(state.Buffer, 0, length);
// Wait for new data.
state.InStream.BeginRead(state.Buffer, 0, state.Buffer.Length, new AsyncCallback(ReadCallback), state);
}
}
public class StreamConnectorState
{
private const int BYTE_ARRAY_SIZE = 4096;
public byte[] Buffer { get; set; }
public Stream InStream { get; set; }
public Stream OutStream { get; set; }
public StreamConnectorState(Stream inStream, Stream outStream)
{
Buffer = new byte[BYTE_ARRAY_SIZE];
InStream = inStream;
OutStream = outStream;
}
}
問題:ここで
は、私はこれらのストリームをリンクするために思い付いたクラスですクライアントがSslStreamの情報と処分を送信して行われた場合
、サーバーはしていませんこれが起こったかどうかの任意の並べ替えの表示をしています。このStreamConnectorクラスは、どんな種類のエラーも発生させることなく、楽しく永遠に実行し続けます。停止する必要のあるインジケータは見つかりません。 (もちろん、ReadCallbackで毎回0の長さになるという事実がありますが、長時間の接続を提供できる必要があるので、これは判断には良い方法ではありません)。
もう1つの可能性ReadCallbackは、利用可能なデータがなくても呼び出されるという問題があります。ストリームの代わりに直接ソケットを使用していた場合、それが違うかどうかはわかりませんが、コードを何度も何度も実行し続けることは非効率的です。
私の質問:
1)ストリームは、クライアント側から閉鎖されている場合に指示する方法はありますか?
2)私がやろうとしていることを行う良い方法はありますか?
2a)非同期読み書きループをより効率的に実行する方法はありますか?
EDIT:ありがとう、Robert。私がストリームを閉じていないので(ストリームを閉じなければならない時を知らせる方法が分からないため)、ループが呼び出され続けていることがわかります。 - それに基づいて、または何か - 切断を検出するために
/// <summary>
/// Connects the read/write operations of two provided streams
/// so long as both of the streams remain open.
/// Disposes of both streams when either of them disconnect.
/// </summary>
public class StreamConnector
{
public StreamConnector(Stream s1, Stream s2)
{
StreamConnectorState state1 = new StreamConnectorState(s1, s2);
StreamConnectorState state2 = new StreamConnectorState(s2, s1);
s1.BeginRead(state1.Buffer, 0, state1.Buffer.Length, new AsyncCallback(ReadCallback), state1);
s2.BeginRead(state2.Buffer, 0, state2.Buffer.Length, new AsyncCallback(ReadCallback), state2);
}
private void ReadCallback(IAsyncResult result)
{
// Get state object.
StreamConnectorState state = (StreamConnectorState)result.AsyncState;
// Check to make sure Streams are still connected before processing.
if (state.InStream.IsConnected() && state.OutStream.IsConnected())
{
// Finish reading data.
int length = state.InStream.EndRead(result);
// Write data.
state.OutStream.Write(state.Buffer, 0, length);
// Wait for new data.
state.InStream.BeginRead(state.Buffer, 0, state.Buffer.Length, new AsyncCallback(ReadCallback), state);
}
else
{
// Dispose of both streams if either of them is no longer connected.
state.InStream.Dispose();
state.OutStream.Dispose();
}
}
}
public class StreamConnectorState
{
private const int BYTE_ARRAY_SIZE = 4096;
public byte[] Buffer { get; set; }
public Stream InStream { get; set; }
public Stream OutStream { get; set; }
public StreamConnectorState(Stream inStream, Stream outStream)
{
Buffer = new byte[BYTE_ARRAY_SIZE];
InStream = inStream;
OutStream = outStream;
}
}
public static class StreamExtensions
{
private static readonly byte[] POLLING_BYTE_ARRAY = new byte[0];
public static bool IsConnected(this Stream stream)
{
try
{
// Twice because the first time will return without issue but
// cause the Stream to become closed (if the Stream is actually
// closed.)
stream.Write(POLLING_BYTE_ARRAY, 0, POLLING_BYTE_ARRAY.Length);
stream.Write(POLLING_BYTE_ARRAY, 0, POLLING_BYTE_ARRAY.Length);
return true;
}
catch (ObjectDisposedException)
{
// Since we're disposing of both Streams at the same time, one
// of the streams will be checked after it is disposed.
return false;
}
catch (IOException)
{
// This will be thrown on the second stream.Write when the Stream
// is closed on the client side.
return false;
}
}
}
タイトルに「C#」という接頭辞を付けることは避けてください。それは何のためのタグですか:) – kprobst
申し訳ありません。 :)私が研究している間、他のいくつかのタイトルで言葉の言葉を見た。それが助けになると思った。ここからタグに固執する。 – zimdanen