查找侦听本地网络上特定端口的服务器

Ton*_*Nam 7 c# networking tcp

我有一个服务器应用程序.我也有一个客户端应用程序.当两个应用程序碰巧在同一网络上时,我能够在应用程序之间建立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比特的部分(总是在掩码的末尾).

在你的例子中:

  • 如果掩码是255.255.255.0,则可能的IP地址范围是192.168.0.*.
  • 如果IP也可以是192.168.1.*然后掩码应该是255.255.0 .0
  • 你也可以有像255.255.255.128这样的面具,范围是192.18.1.[1-126].您可以使用http://www.subnet-calculator.com/了解更多信息.

导致您看到具有这些不同范围的问题的唯一其他可能性是:

  • 你的网络中有更多的DHCP服务器,这真的很糟糕,因为你会遇到"竞争条件".这里的解决方案是通过删除除1个DHCP服务器以外的所有服
  • 您已手动设置IP地址(可能在笔记本电脑上).解决方案是更改为DHCP(如果您需要始终分配给特定计算机的特定IP,请使用静态DHCP)

回到发现检查"某事"是否正在侦听特定端口的问题的问题,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)


Phi*_*mid 0

我假设你有一个服务器。如果您可以保证服务器位置(IP 地址和端口)恒定(或可以查找),那么每个客户端应用程序都可以通过连接到服务器并向服务器“注册”并通知服务器有关 IP 地址和本地端口的信息。打回来。