套接字在读取之前立即关闭
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 字节的消息长度。看起来很明显,但例外情况非常具有误导性。
我正在尝试使用我的 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 字节的消息长度。看起来很明显,但例外情况非常具有误导性。