Home > Mobile >  Socket closes right before reading from it
Socket closes right before reading from it

Time:05-31

I'm trying to use my Socket wrapper to connect to specified whois server to receive some information (yes I know TcpClient exists). To do so I made two classes. One - SocketClient - takes in Socket and has methods which handle all the connection stuff.(I didn't include IDisposable implementation)

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

Second - WhoisResolver - Takes in SocketClient and uses it to send and receive whois info.

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

Here's how I use it:

        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);

Everytime my program tries to read from the stream i get 2 types of exception randomly:

-Unable to read data from the transport connection : An existing connection was forcibly closed by the remote host.

-Tried to read from closed socket.

When i use TcpClient whith buffered stream and stream reader/writer everything works fine.

CodePudding user response:

As stated in the comment above the problem was with the way the message length was read. I thought that the message header was the first 4 bytes but when I read it, it were over 20000000 bytes of message lenght. Seems obvious but the exceptions were pretty misleading.

  • Related