套接字在读取之前立即关闭

Socket closes right before reading from it

我正在尝试使用我的 Socket 包装器连接到指定的 whois 服务器以接收一些信息(是的,我知道 TcpClient 存在)。为此,我制作了两个 类。一个 - SocketClient - 采用 Socket 并具有处理所有连接内容的方法。(我没有包括 IDisposable 实现)

 public class SocketClient : ISocketClient
{
    private const int HEADER_SIZE = 4;
    private Socket _socket;
    private bool disposedValue;

    public SocketClient(Socket socket) { _socket = socket; }

    public virtual Stream Connect(IPEndPoint endPoint)
    {
        _socket.Connect(endPoint);
        return new NetworkStream(_socket);
    }
    public void Send(Stream networkStream, string message, Encoding encoding)
    {
        var bodyBytes = encoding.GetBytes(message);
        var headerBytes = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(bodyBytes.Length + HEADER_SIZE));
        networkStream.Write(headerBytes, 0, HEADER_SIZE);
        networkStream.Write(bodyBytes, 0, bodyBytes.Length);
    }
    public string Receive(Stream networkStream)
    {
        var header = ReadStream(networkStream, HEADER_SIZE);
        var bodyLength = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(header)) -HEADER_SIZE;
        var bodyBytes = ReadStream(networkStream, bodyLength); //Here exception is thrown
        return Encoding.UTF8.GetString(bodyBytes);
    }
    static byte[] ReadStream(Stream networkStream, int bytesToRead)
    {
        var buffer = new byte[bytesToRead];
        var bytesRead = 0;
        while (bytesRead < bytesToRead)
        {
            var bytesReceived = networkStream.Read(buffer, bytesRead, bytesToRead - bytesRead);
            if (bytesReceived == 0)
                throw new SocketIsClosedException("Tried to read from closed socket.");
            bytesRead += bytesReceived;
        }
        return buffer;
    }

其次 - WhoisResolver - 获取 SocketClient 并使用它来发送和接收 whois 信息。

 public class WhoisResolver :  IWhoisResolver
{
    private ISocketClient _socketClient;
    private bool disposedValue;

    public WhoisResolver(ISocketClient socketClient)
    {
        _socketClient = socketClient;
    }
    public  string? Lookup(string fullDomainName, string whoisServerAddress, int whoisServerPort = 43)
    {
        try
        {
            var ip = Dns.GetHostAddresses(whoisServerAddress).First();
            var stream = _socketClient.Connect(new IPEndPoint(ip, whoisServerPort));
            _socketClient.Send(stream, $"{fullDomainName}\r\n",System.Text.Encoding.ASCII); //Here socket is still open
            var response = _socketClient.Receive(stream);
            _socketClient.Disconnect(false);
            return response;
        }catch 
        {
            return null;
        }
    }
}

以下是我的使用方法:

        var whoisServer = "whois.crsnic.net";
        var domainName = "testdomain";
        var tld = "net";
        var socketClient = new SocketClient(new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp));
        var resolver = new WhoisResolver(socketClient);

        var result =  resolver.Lookup($"{domainName}.{tld}", whoisServer);

每次我的程序尝试从流中读取时,我都会随机得到 2 种类型的异常:

- 无法从传输连接读取数据:现有连接被远程主机强行关闭。

-试图从关闭的套接字中读取。

当我使用带缓冲流和流的 TcpClient 时 reader/writer 一切正常。

如上面的评论所述,问题出在读取消息长度的方式上。我以为消息头是前 4 个字节,但当我阅读它时,它超过了 20000000 字节的消息长度。看起来很明显,但例外情况非常具有误导性。