我有一个服务器应用程序.我也有一个客户端应用程序.当两个应用程序碰巧在同一网络上时,我能够在应用程序之间建立tcp连接.因此,假设运行服务器应用程序的计算机正在侦听端口2121上的新连接,并且它具有LAN IP地址192.168.0.120.在运行客户端应用程序的另一台计算机上,我将能够通过提供端口号2121和IP地址192.168.0.120来建立连接.
有没有办法找到网络上正在侦听端口2121的所有计算机?
我现在想的一个算法是:
获取当前计算机的IP地址,并说它出现为192.168.0.145.
现在很可能服务器将侦听IP地址192.168.0.
然后在端口2121上ping 192.168.0.1,在端口2121上ping 192.168.0.2 ...然后继续.
我不知道这种方法是否有效.此外,服务器可能正在侦听IP地址192.168.1.x
那么我必须对我的服务器和客户端应用程序进行哪些更改,以便客户端能够找到侦听端口2121的所有服务器?
小智 5
您提出的算法就是您需要的算法.一个问题是动态生成候选IP地址.
通常,可能的IP地址范围是子网掩码(http://en.wikipedia.org/wiki/Subnetwork)给出的范围.更准确地说,改变的IP部分是在子网掩码中有0比特的部分(总是在掩码的末尾).
在你的例子中:
导致您看到具有这些不同范围的问题的唯一其他可能性是:
回到发现检查"某事"是否正在侦听特定端口的问题的问题,ICMP协议在这里并不是最好的,因为大多数防火墙都过滤广播ICMP和单个ICMP.如果我们真的在谈论服务器,你可能需要手动打开你正在寻找的端口.此外,即使所有计算机都响应,您仍然不知道他们是否托管您想要的服务.
以下解决方案涉及计算候选IP地址的可能范围.之后,您遍历它们以查看是否可以连接到您的端口.
在这个实现中,我按顺序测试,如果主机没有打开,连接超时为30秒,证明非常慢.对于数百名候选人来说,这听起来并不太好.但是,如果大多数主机可用(即使他们没有托管您的服务),一切都会快几倍.
您可以通过找出如何减少此超时(我无法在我的分配时间内找到)或使用 如何配置套接字连接超时中所示的自定义超时来改进程序.您还可以使用多线程并添加在线程安全集合中工作的地址,并从那里开始使用它.
此外,您可以尝试ping(ICMP)之前,但您可能会错过有效的服务器.
static void Main(string[] args)
{
Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
int wantedPort = 21; //this is the port you want
byte[] msg = Encoding.ASCII.GetBytes("type msg here");
foreach (NetworkInterface netwIntrf in NetworkInterface.GetAllNetworkInterfaces())
{
Console.WriteLine("Interface name: " + netwIntrf.Name);
Console.WriteLine("Inteface working: {0}", netwIntrf.OperationalStatus == OperationalStatus.Up);
//if the current interface doesn't have an IP, skip it
if (! (netwIntrf.GetIPProperties().GatewayAddresses.Count > 0))
{
break;
}
//Console.WriteLine("IP Address(es):");
//get current IP Address(es)
foreach (UnicastIPAddressInformation uniIpInfo in netwIntrf.GetIPProperties().UnicastAddresses)
{
//get the subnet mask and the IP address as bytes
byte[] subnetMask = uniIpInfo.IPv4Mask.GetAddressBytes();
byte[] ipAddr = uniIpInfo.Address.GetAddressBytes();
// we reverse the byte-array if we are dealing with littl endian.
if (BitConverter.IsLittleEndian)
{
Array.Reverse(subnetMask);
Array.Reverse(ipAddr);
}
//we convert the subnet mask as uint (just for didactic purposes (to check everything is ok now and next - use thecalculator in programmer mode)
uint maskAsInt = BitConverter.ToUInt32(subnetMask, 0);
//Console.WriteLine("\t subnet={0}", Convert.ToString(maskAsInt, 2));
//we convert the ip addres as uint (just for didactic purposes (to check everything is ok now and next - use thecalculator in programmer mode)
uint ipAsInt = BitConverter.ToUInt32(ipAddr, 0);
//Console.WriteLine("\t ip={0}", Convert.ToString(ipAsInt, 2));
//we negate the subnet to determine the maximum number of host possible in this subnet
uint validHostsEndingMax = ~BitConverter.ToUInt32(subnetMask, 0);
//Console.WriteLine("\t !subnet={0}", Convert.ToString(validHostsEndingMax, 2));
//we convert the start of the ip addres as uint (the part that is fixed wrt the subnet mask - from here we calculate each new address by incrementing with 1 and converting to byte[] afterwards
uint validHostsStart = BitConverter.ToUInt32(ipAddr, 0) & BitConverter.ToUInt32(subnetMask, 0);
//Console.WriteLine("\t IP & subnet={0}", Convert.ToString(validHostsStart, 2));
//we increment the startIp to the number of maximum valid hosts in this subnet and for each we check the intended port (refactoring needed)
for (uint i = 1; i <= validHostsEndingMax; i++)
{
uint host = validHostsStart + i;
//byte[] hostAsBytes = BitConverter.GetBytes(host);
byte[] hostBytes = BitConverter.GetBytes(host);
if (BitConverter.IsLittleEndian)
{
Array.Reverse(hostBytes);
}
//this is the candidate IP address in "readable format"
String ipCandidate = Convert.ToString(hostBytes[0]) + "." + Convert.ToString(hostBytes[1]) + "." + Convert.ToString(hostBytes[2]) + "." + Convert.ToString(hostBytes[3]);
Console.WriteLine("Trying: " + ipCandidate);
try
{
//try to connect
sock.Connect(ipCandidate, wantedPort);
if (sock.Connected == true) // if succesful => something is listening on this port
{
Console.WriteLine("\tIt worked at " + ipCandidate);
sock.Close();
sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
}
//else -. goes to exception
}
catch (SocketException ex)
{
//TODO: if you want, do smth here
Console.WriteLine("\tDIDN'T work at " + ipCandidate);
}
}
}
Console.ReadLine();
}
sock.Close();
}
Run Code Online (Sandbox Code Playgroud)
我假设你有一个服务器。如果您可以保证服务器位置(IP 地址和端口)恒定(或可以查找),那么每个客户端应用程序都可以通过连接到服务器并向服务器“注册”并通知服务器有关 IP 地址和本地端口的信息。打回来。
| 归档时间: |
|
| 查看次数: |
15548 次 |
| 最近记录: |