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.