在 C# 中使用 TcpClient 或通常连接到套接字我如何首先检查我的机器上的某个端口是否空闲?
更多信息: 这是我使用的代码:
TcpClient c;
//I want to check here if port is free.
c = new TcpClient(ip, port);
由于您使用的是TcpClient
,这意味着您正在检查打开的 TCP 端口。System.Net.NetworkInformation命名空间中有很多好的对象可用。
使用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.
你在 Intertube 的错误一端。服务器只能打开一个特定端口。一些代码:
IPAddress ipAddress = Dns.GetHostEntry("localhost").AddressList[0];
try {
TcpListener tcpListener = new TcpListener(ipAddress, 666);
tcpListener.Start();
}
catch (SocketException ex) {
MessageBox.Show(ex.Message, "kaboom");
}
失败:
每个套接字地址(协议/网络地址/端口)通常只允许使用一次。
当您建立 TCP 连接时,4 元组(源 IP、源端口、目标 IP、目标端口)必须是唯一的 - 这是为了确保数据包被传递到正确的位置。
在服务器端还有一个限制,只有一个服务器程序可以绑定到一个传入的端口号(假设一个 IP 地址;多网卡服务器还有其他权力,但我们不需要在这里讨论它们)。
因此,在服务器端,您:
在客户端,它通常更简单一些:
没有要求目标 IP/端口是唯一的,因为这将导致一次只有一个人能够使用 Google,这很可能会破坏他们的商业模式。
这意味着您甚至可以执行多会话 FTP 等奇妙的事情,因为您设置了多个会话,唯一的区别是您的源端口,允许您并行下载块。Torrent 略有不同,因为每个会话的目的地通常不同。
而且,在所有这些胡扯(抱歉)之后,您的具体问题的答案是您不需要指定自由端口。如果您使用未指定源端口的调用连接到服务器,则几乎可以肯定它会在幕后使用零,并且系统会给您一个未使用的端口。
感谢您的提示。我需要相同的功能,但在服务器端检查端口是否正在使用,因此我将其修改为这段代码。
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;
}
TcpClient c;
//I want to check here if port is free.
c = new TcpClient(ip, port);
...我如何首先检查我的机器上的某个端口是否空闲?
我的意思是它没有被任何其他应用程序使用。如果一个应用程序正在使用一个端口,其他人在它空闲之前不能使用它。——阿里
你误解了这里发生的事情。
TcpClient(...) 参数是您希望连接的服务器 ip 和服务器端口。
TcpClient 从可用池中选择一个临时本地端口与服务器通信。无需检查本地端口的可用性,因为它由 winsock 层自动处理。
如果您无法使用上述代码片段连接到服务器,则问题可能是多个中的一个或多个。(即服务器 ip 和/或端口错误,远程服务器不可用等。)
谢谢jro的回答。我不得不调整它以适应我的使用。我需要检查一个端口是否正在被监听,并且不一定是活动的。为此,我更换了
TcpConnectionInformation[] tcpConnInfoArray = ipGlobalProperties.GetActiveTcpConnections();
和
IPEndPoint[] objEndPoints = ipGlobalProperties.GetActiveTcpListeners();.
我迭代了端点数组,检查是否找不到我的端口值。
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);
}
为了回答在 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 关于端口零的评论,我搜索并找到了这个并稍微修改了它。
从可用端口中,我将排除:
使用以下导入:
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
网络统计!这是 Windows 附带的网络命令行实用程序。它显示所有当前已建立的连接和当前正在侦听的所有端口。您可以使用此程序进行检查,但如果您想从代码中执行此操作,请查看 System.Net.NetworkInformation 命名空间?从 2.0 开始,它是一个新的命名空间。那里有一些好东西。但最终,如果您想获得通过命令 netstat 可用的相同类型的信息,您需要生成 P/Invoke ...
该命名空间包含一堆类,您可以使用它们来了解有关网络的信息。
我无法找到那段旧代码,但我认为您可以自己编写类似的代码。一个好的开始是查看IP Helper API。谷歌 MSDN 获取 GetTcpTable WINAPI 函数并使用 P/Invoke 进行枚举,直到获得所需的信息。
ipGlobalProperties.GetActiveTcpConnections()
在侦听状态下不返回连接。
端口可以用于监听,但是没有人连接到它上面描述的方法将不起作用。
如果我没记错的话,你可以使用 System.Network.whatever 来检查。
但是,这总是会导致竞争条件。
检查的规范方法是尝试侦听该端口。如果您收到端口未打开的错误。
我认为这就是为什么 bind() 和 listen() 是两个独立的系统调用的部分原因。
你说
我的意思是它没有被任何其他应用程序使用。如果一个应用程序正在使用一个端口,其他人在它空闲之前不能使用它。
但是,如果有人在那里监听,您总是可以在其他人使用它时连接到一个端口。否则,http 端口 80 将是一团糟。
如果你的
c = new TcpClient(ip, port);
失败了,那么那里什么也听不见。否则,即使其他机器/应用程序有一个对该 ip 和端口开放的套接字,它也会连接。
请注意,您进行检查和尝试建立连接之间的时间窗口可能会占用端口 - 经典TOCTOU。你为什么不尝试连接?如果它失败,那么您知道该端口不可用。
您不必知道本地计算机上打开了哪些端口来连接到某个远程 TCP 服务(除非您想使用特定的本地端口,但通常情况并非如此)。
每个 TCP/IP 连接由 4 个值标识:远程 IP、远程端口号、本地 IP、本地端口号,但您只需要知道远程 IP 和远程端口号即可建立连接。
当您使用创建 tcp 连接时
TcpClient c; c = new TcpClient(remote_ip, remote_port);
您的系统会自动为您的连接分配许多可用的本地端口号之一。你不需要做任何事情。您可能还想检查远程端口是否打开。但是没有比尝试连接它更好的方法了。
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;
}
检查错误代码 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;
}
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++;
}
}