允许客户端应用程序自动连接到同一网络上的服务器应用程序

Posted

技术标签:

【中文标题】允许客户端应用程序自动连接到同一网络上的服务器应用程序【英文标题】:Allow client app to automatically connect to server app on same network 【发布时间】:2016-03-30 05:31:45 【问题描述】:

我已经创建了两个应用程序(一个客户端和一个服务器),只要我将运行服务器应用程序的机器的本地 IP 地址输入到客户端应用程序(在代码中),它们就可以相互通信。

我希望客户端应用程序自动发现运行服务器应用程序的机器的本地 IP 地址并连接到它,这样它们就可以在任何网络上运行,而无需在代码中输入 IP。

这两个应用程序都在同一个网络上运行(即通过 WiFi,而不是 Internet)

这是我目前在客户端应用程序中的内容:

// COMMUNICATE WITH SERVER

    private TcpClient client = new TcpClient();
    private IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse("192.168.2.35"), 8888);

    public Console()
    
        InitializeComponent();
        client.Connect(serverEndPoint);
    

    private void SendMessage(string msg)
    
        NetworkStream clientStream = client.GetStream();

        ASCIIEncoding encoder = new ASCIIEncoding();
        byte[] buffer = encoder.GetBytes(msg);

        clientStream.Write(buffer, 0, buffer.Length);
        clientStream.Flush();
    

在此示例中,我只能连接到运行在“192.168.2.35”上的服务器,我希望它能够在网络上的任何机器上找到运行在端口 8888 上的服务器。

或者,如果这不可能,我希望服务器将其 IP 作为消息(某种形式)广播,并让客户端接收此消息并验证它是服务器并连接到它。

我认为我的第二个示例是执行此操作的正确方法,但我似乎无法理解如何使其工作(我对 C# 还很陌生),以及我发现的任何其他示例我似乎无法使用我的应用程序。

这是我的服务器代码,如果它有助于回答我的问题:

private void Server()
    
        this.tcpListener = new TcpListener(IPAddress.Any, 8888);
        this.listenThread = new Thread(new ThreadStart(ListenForClients));
        this.listenThread.Start();
    

    private void ListenForClients()
    
        this.tcpListener.Start();

        while (true)
        
            TcpClient client = this.tcpListener.AcceptTcpClient();


            connectedClients++;
            lblNumberOfConnections.Text = connectedClients.ToString();

            Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
            clientThread.Start(client);

        

谢谢



编辑:我尝试将THIS 添加到我的项目中,但由于太新,我不确定如何正确实施它,而且它没有让我得到任何结果。


第二次编辑:我已经尝试过几次实现 UDP 广播,但都没有成功。我最近的尝试是实现THIS(减去聊天部分)。我似乎根本无法让 UDP 广播与我的项目一起工作,因为以我目前的技能水平,这似乎超出了我的想象。不幸的是,让我的客户端自动连接到服务器对于我的项目运行来说是 100% 的必要条件......

我的另一个问题,也许最好开始一个单独的问题,但与这个问题有些相关的是:我的客户端 GUI 由一个面板组成,该面板在多个自定义类之间切换,每个类都包含不同的按钮等(工作类似到标签页)与我尝试连接的服务器通信。一旦我弄清楚了 UDP 广播,我是否需要将它分别编码到每个类中?或者有没有办法让我的面板中运行的所有类都连接到同一台服务器?

【问题讨论】:

有人对此有任何指示吗?这是阻碍我参与这个项目的 RC 的主要问题...... 【参考方案1】:

一个简单但可能成本高昂(就网络流量而言)的解决方案是让您的服务器应用程序通过 UDP 广播它的应用程序和连接信息。您的客户端可以侦听具有您的服务器自定义标头的所有广播数据包。假设建立了连接,您可以停止广播。不利的一面是,如果客户端未连接,您将不得不不断广播,如果对广播速度没有限制,这可能会阻塞您的网络。

编辑:这是从 MSDN 文章 https://msdn.microsoft.com/en-us/library/tst0kwb1(v=vs.110).aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-1 生成的简要说明

编辑#2:我已经在我的博客上扩展了这个答案,并提供了可下载的示例项目。文章可以在http://martialdeveloper.com/wordpress/?p=21找到

1.查找您网络的广播 IP

当使用 UDP 向连接到给定网络的所有机器发送数据报时,必须使用特殊的“广播地址”。例如,典型的家庭网络主机/网关 192.168.0.1 的广播地址为 192.168.0.255。如果您的网络与此不同,您可以使用 IPv4 广播地址计算器,如 http://jodies.de/ipcalc 或者阅读 MSDN 上描述广播地址的介绍部分。 https://msdn.microsoft.com/en-us/library/tst0kwb1(v=vs.110).aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-1

2。选择监听/广播端口

您的客户端和服务器上的任何可用端口都可以。 MSDN 示例使用 11000。此端口号用于您的广播器和侦听器。

3.监听器代码

请读者注意。为清楚起见,省略了所有错误处理。

int listenPort = 11000;
bool done = false;

UdpClient listener = new UdpClient(listenPort);
IPEndPoint groupEP = new IPEndPoint(IPAddress.Any,listenPort);


while (!done) // This loop listens for your broadcast packets

    Console.WriteLine("Waiting for broadcast");
    byte[] bytes = listener.Receive( ref groupEP);

    Console.WriteLine("Received broadcast from 0 :\n 1\n",
            groupEP.ToString(),
            Encoding.ASCII.GetString(bytes,0,bytes.Length));

listener.Close();

注意:Console.WriteLine 的第三个参数“Encoding.ASCII...”表示数据报包中通过 UDP 发送的字符串值。这包含发现情况所需的协商信息,例如您希望连接的客户端或服务器的 IP 地址。

4.广播公司代码

Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram,
            ProtocolType.Udp);

IPAddress broadcast = IPAddress.Parse("This string should be the broadcast IP address");  //NOTE: Broadcast IP goes here!!

byte[] sendbuf = Encoding.ASCII.GetBytes("This is the message string to be broadcast"); //Your message to the client/server goes here, I.E. an
         // app/client name or ID and an IP to connect with over TCP

IPEndPoint ep = new IPEndPoint(broadcast, 11000);

s.SendTo(sendbuf, ep);

Console.WriteLine("Message sent to the broadcast address");

注意:这是一个非常简单的示例。广播者可能需要重新广播一段时间,以确保 Listener 接收到它。即使在发送/接收 UDP 数据报之后,也需要进行一些协商以确保正确建立 TCP 连接。

【讨论】:

有没有办法让服务器只在看到客户端时才广播它的 IP? IE。让客户端在打开消息时广播一条消息,让服务器侦听此消息,然后在听到消息时将其 IP 地址发送回客户端。如果这是有道理的...... 当然,UDP 数据包的传输方向是 Server->Client 或 Client->Server 无关紧要,只是为了谁需要监听。您可以轻松地广播客户端 UDP 数据包,告诉服务器打开与客户端的 Tcp 连接。 你有没有机会给我提供一个这样的例子,或者解释如何在我的项目代码中实现它?我现在对这些东西不知所措.. 与其让我的服务器应用程序持续广播(并阻塞我的网络),理想情况下我希望它是我在其他评论中解释的方式:服务器在系统托盘中处于空闲状态 -> 用户打开另一台机器上的客户端->客户端向服务器发送IP地址请求->服务器将其IP发送给客户端->客户端使用接收到的IP地址连接到服务器 @Patrick 这是一个完美的例子。 msdn.microsoft.com/en-us/library/… 在此示例中,您的客户端将是广播者,而服务器将是侦听器。

以上是关于允许客户端应用程序自动连接到同一网络上的服务器应用程序的主要内容,如果未能解决你的问题,请参考以下文章

具有 3G 和 WIFI 网络的 Android 客户端应用程序

如何从不同网络上的android连接到本地apache服务器?(端口转发)

无法从同一网络上的另一台计算机连接到 Grapevine

在同一网络上的另一台计算机上连接到 neo4j?

Docker初学乍练之单主机网络

通过 QT C++ 连接到 SQL server 2005