在网络编程中,经常需要检测一个服务是否可用。通常情况下,可能会编写一个Ping程序来检查设备是否在线。但在某些情况下,不仅需要知道设备是否在线,还需要确定特定的端口是否能够响应TCP Socket连接。本文介绍如何使用C#实现一个TCP端口检测工具,该工具可以在调用其他耗时的子程序之前,检查端口是否响应连接请求。
大多数情况下,都会编写Ping程序来追踪设备是否在线,但在这个场景中,需要确保在调用其他一些耗时的子程序之前,端口能够响应TCP Socket连接。为了解决这个问题,选择了使用Sockets.TcpClient类中提供的异步BeginConnect函数,并通过线程来管理可能出现的长时间等待。然而,这种方法在代码层面上显得相当丑陋,效率也不高,导致了大量的异常捕获。
为了解决这个问题,编写了一个小型的静态函数,其工作原理类似于PortQry或NMap工具。尝试使用BeginConnect子程序进行连接,然后等待直到超时,假设端口不再响应并将其标记为已过滤。这种方法不仅响应迅速,而且在BackgroundWorker中使用时线程表现良好。
以下是该函数的基本实现:
public static SocketResponse SocketPoll(
string Node = "127.0.0.1",
int tcpPort = 135,
int tcpTimeout = 2500
)
{
if (Node == null || Node.Trim() == "")
Node = "127.0.0.1";
if (tcpPort < 0) tcpPort = 135;
if (tcpTimeout < 0) tcpTimeout = 2500;
IPAddress ipNode = DetermineIP(Node);
TcpClient tSocket = new TcpClient();
DateTime endTime = DateTime.Now.AddMilliseconds(tcpTimeout);
IAsyncResult ar = tSocket.BeginConnect(ipNode, tcpPort, null, tSocket);
while (DateTime.Now < endTime)
{
if (ar.IsCompleted)
{
Socket s = tSocket.Client;
try
{
if (!s.Poll(100, SelectMode.SelectError))
{
return SocketResponse.LISTENING;
}
s.EndConnect(ar);
tSocket.Close();
}
catch (System.Net.Sockets.SocketException SocketEx)
{
switch ((SocketError)Enum.ToObject(typeof(SocketError), SocketEx.ErrorCode))
{
case SocketError.ConnectionRefused:
return SocketResponse.NOT_LISTENING;
case SocketError.HostUnreachable:
case SocketError.HostDown:
case SocketError.NetworkUnreachable:
return SocketResponse.UNREACHABLE;
default:
return SocketResponse.OTHER;
}
}
}
Thread.Sleep(10);
}
return SocketResponse.FILTERED;
}
在上述代码中,首先对输入参数进行了校验和默认值设置。然后,创建了一个TcpClient实例,并使用BeginConnect方法尝试异步连接到指定的IP地址和端口。设置了一个结束时间,如果在指定的超时时间内连接完成,检查连接状态并相应地返回结果。如果在超时时间内没有完成连接,返回FILTERED状态。