gpt4 book ai didi

c# - 是否可以检测到 Stream 是否已被客户端关闭?

转载 作者:太空狗 更新时间:2023-10-29 17:57:30 25 4
gpt4 key购买 nike

情况简介:

我有一项服务可以接收信息并通过套接字发送回复。连接不安全。我想设置另一个可以为这些连接提供 TLS 的服务——这个新服务将提供一个端口并根据提供的客户端证书分发连接。我不想使用 Stunnel 有几个原因,其中之一是每个接收端口需要一个转发端口。

我目前正在尝试实现的解决方案:

本质上,我试图将 SslStream(传入)与 NetworkStream(传出 - 可能是套接字,但我将其放入 NetworkStream 以匹配传入)结合起来,并为两者链接读/写操作.此链接将提供客户端(通过 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长度的事实,但我需要能够提供长时间运行的连接,所以这不是一个很好的判断方式。)

另一个潜在的问题是即使没有可用数据也会调用 ReadCallback。不确定如果我直接使用套接字而不是流是否会有所不同,但一遍又一遍地继续运行该代码似乎效率不高。

我的问题:

1) 有没有办法从客户端判断 Stream 是否已关闭?

2) 是否有更好的方法来完成我想做的事情?

2a) 是否有更有效的方式来运行异步读/写循环?

编辑:谢谢,罗伯特。结果循环一直被调用,因为我没有关闭 Streams(因为不知道如何判断何时需要关闭 Streams)。我提供了完整的代码解决方案,以防其他人遇到此问题:

/// <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;
}
}
}

最佳答案

您必须尝试读取或写入套接字——或任何基于它的东西——来检测断开连接。

尝试写入将抛出异常/返回错误(取决于您的语言范例)或可能只写入 0 个字节。尝试读取将引发异常/返回错误(再次取决于您的语言范例)或返回 null

值得注意的是,如果您使用的是基于选择的服务器模型,断开连接的套接字在断开连接时显示为可读——即返回选择——然后您尝试从中读取并得到错误或

关于c# - 是否可以检测到 Stream 是否已被客户端关闭?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9707314/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com