【问题标题】:How do I get all servers' IP which are listening on specific port LAN?如何获取正在侦听特定端口 LAN 的所有服务器的 IP?
【发布时间】:2012-03-30 14:39:28
【问题描述】:

如何获取所有在 LAN 中侦听特定端口(例如:9090)的服务器 IP 我已经阅读了一些关于多播的基本信息,anycastunicastbroadcast,似乎 broadcast 是我的应用程序的意思。 我在想两个想法..

  • 使用 TCP 协议在端口 9090 上并行连接到所有 IP 地址 (192.168.1.1-254),并为连接超时设置一点时间。只是为了检查是否有任何回应。 (但这似乎不是一个好主意)
  • 使用 UDP 协议并广播类似“hello”的消息并检查响应,然后获取所有响应的 IP 地址。

    那么我应该选择哪个想法,有更好的想法吗? 我也想知道我的广播消息是否被接收到服务器以及如何获取它的IP地址。

  • 【问题讨论】:

    标签: c# udp client-server broadcast lan


    【解决方案1】:

    我已经使用 TCP 来搜索所有正在侦听特定端口的服务器。 它不是一个闲置的解决方案,但它对我有用。

    我创建了一个带有公共函数 Initialize 的 userControl 来传递我要扫描服务器的端口。

    public ServerDiscovery()
        {
            InitializeComponent();
        //    statusLabel.Image = imageState.Images[2];
            timer.Elapsed += timer_tick;
        }
        int port = 0;
        bool busy = false;  // to tell that the function is busy with scanning.
        public void Initialize(int port)
        {
            this.port = port;
        }
    
        System.Timers.Timer timer = new System.Timers.Timer(5000);
        List<SocketAsyncEventArgs> list = new List<SocketAsyncEventArgs>();
        // this list to hold all sockets that created to connect to IP .. to DISPOSE it later
        HashSet<string> usedIP = new HashSet<string>();
        //usedIP will be explained later. 
    
        public IPEndPoint getAddress()
        {   //this function to get the IPEndPoint of the selected server from listview.
            if (listServer.SelectedItems.Count > 0)
            {
                if (listServer.SelectedItems[0].ImageIndex == 0)
                {
                    ListViewItem item = listServer.SelectedItems[0];
                    IPEndPoint ep = new IPEndPoint(IPAddress.Parse(item.SubItems[1].Text), port);
                    return ep;
                }
            }
            return null;
        }
    
        public void Refresh()   //to scan for servers
        {
            if (!busy)
            {
                usedIP.Clear();
                listServer.Items.Clear();
        //       statusLabel.Text = "Scanning for servers.";
        //        statusLabel.Image = Image.FromFile("loading.gif");
        //        btnRefresh.Enabled = false;
                busy = true;
                timer.Start();
                IPAddress[] IpA = Dns.GetHostByName(Dns.GetHostName()).AddressList;
                for (int j = 0; j < IpA.Length ; j++)
                {
                    if (IpA[j].AddressFamily == AddressFamily.InterNetwork)  // to make sure it's an IPV4
                    {
                        string scanIP = IpA[j].ToString().Substring(0, IpA[j].ToString().LastIndexOf(".")) + ".";
                        if (!usedIP.Contains(scanIP))
                 //usedIP is a hashset that holds the first 3 parts on an ip (ex:"192.168.1." from "192.168.1.30") i used this to avoid scanning the same ip addresses more than once .. like if i had a wireless network ip ("192.168.1.5") and an Ethernet Network ip ("192.168.1.5"). so with that hashset it will scan once.
                        {
                            usedIP.Add(scanIP);
                            Parallel.For(1, 255, i =>
                            {
                                Scan(scanIP + i);
                            });
                        }
                    }
                }
            }
        }
    
        private void Scan(string ipAdd)
        {
            Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            SocketAsyncEventArgs e = new SocketAsyncEventArgs();
            e.RemoteEndPoint = new IPEndPoint(IPAddress.Parse(ipAdd), port);
            e.UserToken = s;
            e.Completed += new EventHandler<SocketAsyncEventArgs>(e_Completed);
            list.Add(e);   // add the created socket to a list to dispose when time is up.
            s.ConnectAsync(e);
        }
    
        private void e_Completed(object sender, SocketAsyncEventArgs e)
        {
            if (e.ConnectSocket != null) //if there's a responce from the server [e.ConnectSocket] will not be equal null.
            {
                StreamReader sr = new StreamReader(new NetworkStream(e.ConnectSocket));
                ListViewItem item = new ListViewItem();
                string[] cmd = sr.ReadLine().Split('<');  in my server constructor this line will receive a string like "PC_NAME<Available"  ..
                item.Text = cmd[0];
                item.SubItems.Add(((IPEndPoint)e.RemoteEndPoint).Address.ToString());
                item.SubItems.Add(cmd[1]);
                if (cmd[1] == "Busy")
                    item.ImageIndex = 1;
                else
                    item.ImageIndex = 0;
                AddServer(item);
                list.Remove(e);  //active server should be remove from the list that holds the sockets and disposed.. because there's no need to keep connection after showing that this server is active. 
                ((Socket)e.UserToken).Dispose();
            }
        }
    
        delegate void AddItem(ListViewItem item);
        private void AddServer(ListViewItem item)
        {
            if (InvokeRequired)
            {
                Invoke(new AddItem(AddServer), item);  //just to add an item from a background thread.
                return;
            }
            listServer.Items.Add(item);
        }
    
        private void timer_tick(object sender, EventArgs e)
        {
            busy = false;     //when time's up .. set busy to false so we can scan again
            timer.Stop();
            foreach (var s in list) //dispose all sockets that's trying to connect and waiting for a response
            {
                try
                {
                    ((Socket)s.UserToken).Dispose();
                }
                catch { }
            }
            //this.Invoke((MethodInvoker)delegate        // for design
           // {
           //     btnRefresh.Enabled = true;
           //     btnRefresh.BorderStyle = Border3DStyle.Raised;
           //     statusLabel.Text = "Ready.";
           //     statusLabel.Image = imageState.Images[2];
           // });
        }
    
        private void btnRefresh_Click(object sender, EventArgs e)
        {
           // btnRefresh.BorderStyle = Border3DStyle.Sunken;
            Refresh();
        }
    
       // private void listServer_KeyUp(object sender, KeyEventArgs e)
       // {
        //    if (e.KeyCode == Keys.F5)
        //    {
         //       btnRefresh_Click(sender, (EventArgs)e);
         //   }
      //  }
    
    
    }
    

    同样,这不是一个适用于任何情况的理想解决方案,但对我来说效果很好。

    【讨论】:

    • 可以分享完整的代码吗?也许将其上传到保管箱或谷歌驱动器
    猜你喜欢
    • 1970-01-01
    • 2011-04-03
    • 1970-01-01
    • 2023-03-12
    • 1970-01-01
    • 1970-01-01
    • 2021-12-16
    • 2017-02-15
    • 1970-01-01
    相关资源
    最近更新 更多