在 C # 中,如何检查 TCP 端口是否可用?

在 C # 中使用 TcpClient 或通常连接到套接字如何首先检查某个端口是否在我的机器上是空闲的?

更多信息: 这是我使用的代码:

TcpClient c;
//I want to check here if port is free.
c = new TcpClient(ip, port);
234524 次浏览

Netstat!这是一个附带窗口的网络命令行实用程序。它显示当前建立的所有连接和当前正在监听的所有端口。您可以使用这个程序进行检查,但是如果您想从代码中进行检查,请查看系统。网。网络信息命名空间 NetworkInformation? ?从2.0开始,这是一个新的名称空间。那里有些好东西。但是最终,如果您希望获得通过命令 netstat 可用的同类信息,则需要将结果输出到 P/Invoke..。

更新: System.Net.NetworkInformation

该命名空间包含许多类,您可以使用这些类来查找有关网络的信息。

我找不到那段旧代码,但我认为你可以自己编写类似的代码。一个好的开始是检查 IP 助手 API。Google MSDN 的 GetTcpTable WINAPI 函数和使用 P/Invoke 枚举,直到您有所需的信息。

string hostname = "localhost";
int portno = 9081;
IPAddress ipa = (IPAddress) Dns.GetHostAddresses(hostname)[0];




try
{
System.Net.Sockets.Socket sock = new System.Net.Sockets.Socket(System.Net.Sockets.AddressFamily.InterNetwork, System.Net.Sockets.SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp);
sock.Connect(ipa, portno);
if (sock.Connected == true)  // Port is in use and connection is successful
MessageBox.Show("Port is Closed");
sock.Close();


}
catch (System.Net.Sockets.SocketException ex)
{
if (ex.ErrorCode == 10061)  // Port is unused and could not establish connection
MessageBox.Show("Port is Open!");
else
MessageBox.Show(ex.Message);
}

你说

我的意思是,它没有被任何人使用 其他申请 正在使用一个其他人不能使用的端口 直到它变得自由。

但是你总是可以连接到一个端口,而其他人正在使用它,如果有东西在那里监听。否则,http 端口80将是一团糟。

如果你

   c = new TcpClient(ip, port);

如果失败了,那里就没人听了。否则,它将连接,即使其他一些机器/应用程序有一个打开到 IP 和端口的套接字。

因为您使用的是 TcpClient,这意味着您正在检查打开的 TCP 端口。在 网络信息系统名称空间中有许多好的对象可用。

使用 IPGlobalProperties对象获取 TcpConnectionInformation对象的数组,然后可以查询有关端点 IP 和端口的信息。


 int port = 456; //<--- This is your value
bool isAvailable = true;


// Evaluate current system tcp connections. This is the same information provided
// by the netstat command line application, just in .Net strongly-typed object
// form.  We will look through the list, and if our port we would like to use
// in our TcpClient is occupied, we will set isAvailable to false.
IPGlobalProperties ipGlobalProperties = IPGlobalProperties.GetIPGlobalProperties();
TcpConnectionInformation[] tcpConnInfoArray = ipGlobalProperties.GetActiveTcpConnections();


foreach (TcpConnectionInformation tcpi in tcpConnInfoArray)
{
if (tcpi.LocalEndPoint.Port==port)
{
isAvailable = false;
break;
}
}


// At this point, if isAvailable is true, we can proceed accordingly.

你站错地方了。服务器只能打开一个特定的端口。一些代码:

  IPAddress ipAddress = Dns.GetHostEntry("localhost").AddressList[0];
try {
TcpListener tcpListener = new TcpListener(ipAddress, 666);
tcpListener.Start();
}
catch (SocketException ex) {
MessageBox.Show(ex.Message, "kaboom");
}

失败的原因:

每个套接字地址(协议/网络地址/端口)通常只允许使用一次。

ipGlobalProperties.GetActiveTcpConnections()在监听状态中不返回连接。

端口可以用来监听,但是如果没有人连接到它,上面描述的方法将无法工作。

TcpClient c;


//I want to check here if port is free.
c = new TcpClient(ip, port);

... 我怎样才能首先检查某个端口是否在我的机器上是空闲的?

我的意思是,它没有被任何其他应用程序使用。 如果一个应用程序正在使用一个端口,其他人不能使用它,直到它变得免费

你误会了这里发生的事。

TcpClient (...)参数是您希望连接到的服务器 ip 和服务器端口。

TcpClient 从可用池中选择一个临时本地端口与服务器通信。不需要检查本地端口的可用性,因为它是由 winsock 层自动处理的。

如果您不能使用上面的代码片段连接到服务器,那么问题可能是多个代码片段中的一个或多个。(例如,服务器 ip 和/或端口错误,远程服务器不可用,等等)

在设置 TCP 连接时,4-tuple (source-ip、 source-port、 dest- ip、 dest- port)必须是唯一的——这是为了确保数据包被传递到正确的位置。

服务器方面还有一个进一步的限制,即只有一个服务器程序可以绑定到传入端口号(假设有一个 IP 地址; 多 NIC 服务器具有其他能力,但我们不需要在这里讨论它们)。

因此,在服务器端,您:

  • 创建一个插座。
  • 将该套接字绑定到端口。
  • 监听那个港口。
  • 接受该端口上的连接。 并且可能有多个连接进入(每个客户端一个)。

在客户端,情况通常要简单一些:

  • 创建一个插座。
  • 打开连接。 当客户端打开连接时,它指定 服务器的 ip 地址和端口。它 可以指定其源端口,但通常使用零,这导致系统自动分配一个自由端口。

没有要求目的地 IP/端口是唯一的,因为这将导致每次只有一个人能够使用 Google,这将很好地破坏他们的商业模式。

这意味着您甚至可以完成多会话 FTP 这样的奇妙事情,因为您设置了多个会话,其中唯一的区别是您的源端口,允许您并行下载块。Torrent 有点不同,因为每个会话的目的地通常是不同的。

而且,在所有这些废话(对不起)之后,对于您的具体问题的答案是,您不需要指定一个自由端口。如果您使用一个没有指定源端口的调用连接到一个服务器,那么它几乎肯定会在掩护下使用零,而系统会给您一个未使用的端口。

请注意您进行检查的时间窗口和您尝试连接的时刻之间的一些进程可能采取端口-经典的 TOCTOU。你为什么不试着和他们交流呢?如果它失败了,那么您就知道端口不可用。

您不必知道本地计算机上打开了哪些端口来连接到某些远程 TCP 服务(除非您想使用特定的本地端口,但通常情况并非如此)。

每个 TCP/IP 连接由4个值标识: 远程 IP、远程端口号、本地 IP、本地端口号,但是您只需要知道远程 IP 和远程端口号就可以建立连接。

创建 tcp 连接时,使用

TcpClient c;
c = new TcpClient(remote_ip, remote_port);


您的系统将自动为您的连接分配许多免费本地端口号之一。你什么都不用做。 您可能还想检查远程端口是否打开。但是没有比试图与它联系更好的方法了。

如果我没有弄错的话,您可以使用 System.Network.whatever 进行检查。

但是,这将始终引发竞态条件。

规范的检查方法是尝试监听该端口。如果您得到一个错误,端口没有打开。

I 好好想想这是 bind ()和 listen ()是两个独立系统调用的原因之一。

感谢@jro 回答。我不得不调整它的用途。我需要检查一个端口是否正在被监听,并且不一定处于活动状态。为了这个,我替换了

TcpConnectionInformation[] tcpConnInfoArray = ipGlobalProperties.GetActiveTcpConnections();

IPEndPoint[] objEndPoints = ipGlobalProperties.GetActiveTcpListeners();.

我迭代了端点数组,检查是否找到了端口值。

谢谢你的建议。我需要相同的功能,但在服务器端检查端口是否正在使用,所以我修改了这段代码。

 private bool CheckAvailableServerPort(int port) {
LOG.InfoFormat("Checking Port {0}", port);
bool isAvailable = true;


// Evaluate current system tcp connections. This is the same information provided
// by the netstat command line application, just in .Net strongly-typed object
// form.  We will look through the list, and if our port we would like to use
// in our TcpClient is occupied, we will set isAvailable to false.
IPGlobalProperties ipGlobalProperties = IPGlobalProperties.GetIPGlobalProperties();
IPEndPoint[] tcpConnInfoArray = ipGlobalProperties.GetActiveTcpListeners();


foreach (IPEndPoint endpoint in tcpConnInfoArray) {
if (endpoint.Port == port) {
isAvailable = false;
break;
}
}


LOG.InfoFormat("Port {0} available = {1}", port, isAvailable);


return isAvailable;
}
    public static bool TestOpenPort(int Port)
{
var tcpListener = default(TcpListener);


try
{
var ipAddress = Dns.GetHostEntry("localhost").AddressList[0];


tcpListener = new TcpListener(ipAddress, Port);
tcpListener.Start();


return true;
}
catch (SocketException)
{
}
finally
{
if (tcpListener != null)
tcpListener.Stop();
}


return false;
}
test_connection("ip", port);




public void test_connection(String hostname, int portno) {
IPAddress ipa = (IPAddress)Dns.GetHostAddresses(hostname)[0];
try {
System.Net.Sockets.Socket sock = new System.Net.Sockets.Socket(System.Net.Sockets.AddressFamily.InterNetwork, System.Net.Sockets.SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp);
sock.Connect(ipa, portno);
if (sock.Connected == true) {
MessageBox.Show("Port is in use");
}


sock.Close();
}
catch (System.Net.Sockets.SocketException ex) {
if (ex.ErrorCode == 10060) {
MessageBox.Show("No connection.");
}
}
}

试试这个,在我的例子中,创建对象的端口号不可用,所以我想出了这个

IPEndPoint endPoint;
int port = 1;
while (true)
{
try
{
endPoint = new IPEndPoint(IPAddress.Any, port);
break;
}
catch (SocketException)
{
port++;
}
}

从可用的端口我将排除:

  • 活动的 TCP 连接
  • 活动 TCP 侦听器
  • 主动 UDP 侦听器

进口货物如下:

using System.Net.NetworkInformation;

您可以使用以下函数检查端口是否可用:

private bool isPortAvalaible(int myPort)
{
var avalaiblePorts = new List<int>();
var properties = IPGlobalProperties.GetIPGlobalProperties();


// Active connections
var connections = properties.GetActiveTcpConnections();
avalaiblePorts.AddRange(connections);


// Active tcp listners
var endPointsTcp = properties.GetActiveTcpListeners();
avalaiblePorts.AddRange(endPointsTcp);


// Active udp listeners
var endPointsUdp = properties.GetActiveUdpListeners();
avalaiblePorts.AddRange(endPointsUdp);


foreach (int p in avalaiblePorts){
if (p == myPort) return false;
}
return true;
}

我为那些使用 VB.NET的人提供一个类似的函数:

Imports System.Net.NetworkInformation
Private Function isPortAvalaible(ByVal myPort As Integer) As Boolean
Dim props As IPGlobalProperties = IPGlobalProperties.GetIPGlobalProperties()


' ignore active connections
Dim tcpConnInfoArray() As TcpConnectionInformation = props.GetActiveTcpConnections()
For Each tcpi As Net.NetworkInformation.TcpConnectionInformation In tcpConnInfoArray
If tcpi.LocalEndPoint.Port = myPort Then
Return False
End If
Next tcpi


' ignore active TCP listeners
Dim activeTcpListeners() As Net.IPEndPoint = props.GetActiveTcpListeners
For Each tcpListener As Net.IPEndPoint In activeTcpListeners
If tcpListener.Port = myPort Then
Return False
End If
Next tcpListener


' ignore active UPD listeners
Dim activeUdpListeners() As Net.IPEndPoint = props.GetActiveUdpListeners
For Each udpListener As Net.IPEndPoint In activeUdpListeners
If udpListener.Port = myPort Then
Return False
End If
Next udpListener


Return True
End Function

检查错误代码10048

try
{
TcpListener tcpListener = new TcpListener(ipAddress, portNumber);
tcpListener.Start();
}
catch(SocketException ex)
{
if(ex.ErrorCode == 10048)
{
MessageBox.Show("Port " + portNumber + " is currently in use.");
}
return;
}

为了回答在 dotnet core 3.1中找到一个空闲端口(这是我在单元测试中需要的)的确切问题,我提出了这个问题

public static int GetAvailablePort(IPAddress ip) {
TcpListener l = new TcpListener(ip, 0);
l.Start();
int port = ((IPEndPoint)l.LocalEndpoint).Port;
l.Stop();
Log.Info($"Available port found: {port}");
return port;
}

注意: 基于@user207421关于端口0的注释,我搜索并找到了 这个,并对其稍作修改。

我只是需要验证一个端口是否可用于侦听。将上面的@Melloware示例压缩为一行程序作为静态方法,严格说来是为了指示端口是否可用,这对我来说是可行的(。NET6).

using System.Net.NetworkInformation;


namespace MyNamespace
{
public static class NetworkValidation
{
public static bool IsListeningPortAvailable(int port) =>
!IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners().Any(x => x.Port == port);
}
}

作为简单的控制台应用程序实现:

using MyNamespace;
int port = 5000;
var available = NetworkValidation.IsListeningPortAvailable(port);


Console.WriteLine($"Port:{port} available == {available}");