【问题标题】:How to communicate between two process and two hosts using UDP datagrams on Android如何在 Android 上使用 UDP 数据报在两个进程和两个主机之间进行通信
【发布时间】:2018-05-01 17:08:27
【问题描述】:

我的分布式应用程序,有不同的主机,需要在同一个局域网内找到本地服务器。

我使用 NsdManager 检测本地服务器的成功有限,这是一种可行的方法,但通常,服务器仍然未被检测到。我正在寻找更好的解决方案,更可靠的解决方案。

然后我尝试多播 UDP 数据包,从同一进程中检测到这些数据包没有问题。 (我的单元测试同时使用客户端和服务器实例)。这很好用。相同的类将不允许我的客户端检测我在同一设备上运行的服务器(客户端和服务器是单独的进程应用程序)。

然后我使用广播地址改变了我的方法,再次,在同一个进程中,单元测试很好,但是在两个不同的进程中,没有找到服务器。

正如我所说,代码在同一个进程中运行良好,但在两个不同的进程中运行时,或者在同一 LAN 中的两个不同的客户端/服务器主机上运行时它们不起作用。

注意:我的局域网是高端WiFi rooter,没有特殊设置。

有人知道可能是什么问题吗?

请注意,我的清单包括客户端和服务器应用程序的以下设置:

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />

请注意,为了让我的客户端检测在同一主机上运行的服务器,我已经在使用 TCP 套接字,但我需要检测局域网中的任何服务器。

【问题讨论】:

  • 问题出在您的代码中。编辑您的 Q w.r.t mcve。 UDP 通信不能依赖于任何类型的进程。
  • 我的代码工作得很好,包括多播和广播的 UDP 数据包,只要它在我的单元测试中,客户端和服务器都在同一个进程中运行。当运行两个单独的客户端和服务器应用程序时,因此是两个单独的进程,我的代码无法读取任何数据报。
  • 当服务器和客户端都在同一个进程中时,完全相同的代码可以很好地读取数据报。问题在于两个应用程序都在不同的主机和应用程序中运行。

标签: java android udp broadcast multicast


【解决方案1】:

UDP 通信不能依赖于任何类型的进程。问题出在你的代码上。

【讨论】:

    【解决方案2】:

    @Onik 说的很对,

    制作一个最小、完整且可验证的示例让我能够找到问题所在。

    这里是任何可能感兴趣的人的代码:

    package com.example;
    
    import java.net.DatagramPacket;
    import java.net.DatagramSocket;
    import java.net.InetAddress;
    import java.net.InterfaceAddress;
    import java.net.NetworkInterface;
    import java.util.Enumeration;
    import java.util.List;
    
    import android.util.Log;
    
    /**
     * Minimal, Complete, and Verifiable example for broadcasting UDP sockets, send thread.
     * 
     * Loosely based on:
     * 
     * https://jackiexie.com/2015/07/15/network-discovery-using-udp-broadcast-java/
     */
    public class BroadcastSender extends Thread {
    
    public static final String TAG = "BroadcastSender";
    
    public static final int TEST_PORT_NUMBER            = 1234;
    public static final int TEST_COUNT                  = 10;
    public static final int DELAY_BETWEEN_PACKETS_MS    = 500;
    
    public static final int TEST_TIME_MS    =   TEST_COUNT * DELAY_BETWEEN_PACKETS_MS;
    
    private DatagramSocket mSocket;
    
    public BroadcastSender() {
    
        super( TAG );
    }
    
    public static InetAddress getBroadcastAddress() {
    
        try {
            Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
    
            while( interfaces.hasMoreElements() ) {
    
                NetworkInterface current = interfaces.nextElement();
    
                try {
    
                    if( !current.isUp()  )
                        continue;
    
                    if( current.isLoopback() )
                        continue;
    
                    List<InterfaceAddress> addresses = current.getInterfaceAddresses();
    
                    if( addresses == null ) {
    
                        log("getBroadcastAddress can not get addresses from "+current);                     
                        continue;
                    }
    
                    for( InterfaceAddress oneInterfaceAddress : addresses ) {
    
                        InetAddress bcast = oneInterfaceAddress.getBroadcast();
    
                        if( bcast != null )
                            return bcast;
                    }
                }
                catch( Exception ex) {
    
                    log( "getBroadcastAddress exception "+ex+" stack "+Log.getStackTraceString(ex) );
                }               
            }
        }
        catch( Exception ex) {
    
            log( "getBroadcastAddress exception "+ex+" stack "+Log.getStackTraceString(ex) );
        }
    
        return null;
    }       
    
    @Override
    public void run() {
    
        try {
    
            mSocket = new DatagramSocket();
            mSocket.setBroadcast(true);         
    
            InetAddress interfaceBroadcast = getBroadcastAddress(); 
    
            InetAddress broadcastAddr = InetAddress.getByName("255.255.255.255");                   
    
            String payloadStr   = "payload pid="+android.os.Process.myPid();
            byte payloadBytes[] = payloadStr.getBytes();
    
            for( int packet = 0; packet < TEST_COUNT; packet++) {
    
                // First send to 255.255.255.255
                DatagramPacket dp = new DatagramPacket(payloadBytes, payloadBytes.length, broadcastAddr, TEST_PORT_NUMBER);    
                mSocket.send(dp);
    
                // Then send to whatever address we have for interfaceBroadcast
                if( interfaceBroadcast != null ) {
    
                    dp = new DatagramPacket(payloadBytes, payloadBytes.length, interfaceBroadcast, TEST_PORT_NUMBER);
                    mSocket.send(dp);
                }
    
                log("sent #"+packet+" with "+payloadBytes.length+" bytes \""+payloadStr+"\"");
    
                synchronized (this) {
    
                    try {
    
                        wait(DELAY_BETWEEN_PACKETS_MS);
                    }
                    catch( InterruptedException ex) {
    
                        log("run exeption "+ex.toString());
                    }
                }
            }
    
            mSocket.close();            
            mSocket = null;                 
        }
        catch( Exception ex) {
    
            log("run exception "+ex.toString()+" stack "+Log.getStackTraceString(ex));
        }
    }
    
    private static void log( String message) {
    
        Log.d(TAG, message);
    }
    
    
    /**
     * Minimal, Complete, and Verifiable example for broadcasting UDP sockets, receive thread.
     * Loosely based on:
     * 
     * https://jackiexie.com/2015/07/15/network-discovery-using-udp-broadcast-java/
     */
    public static class BroadcastReceiver extends Thread {
    
        public static final String TAG = "BroadcastReceiver";
    
        public int totalReceived = 0;
    
        public BroadcastReceiver() {
    
            super( TAG );
        }
    
        @Override
        public void run() {
    
            final String methodName = "run";
    
            try {
    
                byte messageBytes[] = new byte[1500];
    
                DatagramPacket dp = new DatagramPacket(messageBytes, messageBytes.length);
    
                DatagramSocket mSocket = new DatagramSocket(TEST_PORT_NUMBER);
                mSocket.setSoTimeout(DELAY_BETWEEN_PACKETS_MS); 
                mSocket.setBroadcast(true);
    
                while( totalReceived < TEST_COUNT ) {
    
                    try {                       
                        // Get one UDP packet
                        mSocket.receive(dp);
    
                        if( dp.getLength() > 0 ) {
    
                            totalReceived++;
    
                            String payloadStr = new String(dp.getData());
                            log( "received #"+totalReceived+" : \""+payloadStr+"\"");
                        }                   
                    }
                    catch( Exception ex) {
    
                        log("receive exception "+ex.toString());
                    }
                }               
    
                mSocket.close();            
                mSocket = null;             
                log(methodName+" socket closed.");
            }
            catch( Exception ex) {
    
                log(methodName+" exception "+ex.toString());
            }
        }
    
        private static void log( String message) {
    
            Log.d(TAG, message);
        }
    }
    
    public static boolean unit_test() {
    
        try {
    
            BroadcastSender     sender = new BroadcastSender();
            sender.start();
    
            BroadcastReceiver   receiver = new BroadcastReceiver();
            receiver.start();
            log( "joining "+sender.getName());
            sender.join(TEST_TIME_MS);
    
            log( "joining "+receiver.getName());
            receiver.join(TEST_TIME_MS);
    
            boolean success = receiver.totalReceived >= TEST_COUNT;
            log( "unit test results="+success);
            return success;
    
        }
        catch( Exception ex ) {
    
            log( "unit test exception "+ex);
            return false;
        }
    }
    /*
     * Log output:
     * 
    D 2017-11-17 19:10:56.809 6228 BroadcastSender sent #0 with 16 bytes "payload pid=6228"
    D 2017-11-17 19:10:57.313 6228 BroadcastSender sent #1 with 16 bytes "payload pid=6228"
    D 2017-11-17 19:10:57.314 6228 BroadcastReceiver received #1 : "payload pid=6228"
    D 2017-11-17 19:10:57.315 6228 BroadcastReceiver received #2 : "payload pid=6228"
    D 2017-11-17 19:10:57.816 6228 BroadcastSender sent #2 with 16 bytes "payload pid=6228"
    D 2017-11-17 19:10:57.817 6228 BroadcastReceiver received #3 : "payload pid=6228"
    D 2017-11-17 19:10:57.818 6228 BroadcastReceiver received #4 : "payload pid=6228"
    D 2017-11-17 19:10:58.319 6228 BroadcastReceiver received #5 : "payload pid=6228"
    D 2017-11-17 19:10:58.319 6228 BroadcastSender sent #3 with 16 bytes "payload pid=6228"
    D 2017-11-17 19:10:58.321 6228 BroadcastReceiver received #6 : "payload pid=6228"
    D 2017-11-17 19:10:58.822 6228 BroadcastSender sent #4 with 16 bytes "payload pid=6228"
    D 2017-11-17 19:10:58.822 6228 BroadcastReceiver received #7 : "payload pid=6228"
    D 2017-11-17 19:10:58.823 6228 BroadcastReceiver received #8 : "payload pid=6228"
    D 2017-11-17 19:10:59.325 6228 BroadcastReceiver receive exception java.net.SocketTimeoutException: Receive timed out
    D 2017-11-17 19:10:59.326 6228 BroadcastReceiver received #9 : "payload pid=6228"
    D 2017-11-17 19:10:59.327 6228 BroadcastReceiver received #10 : "payload pid=6228"
    D 2017-11-17 19:10:59.325 6228 BroadcastSender sent #5 with 16 bytes "payload pid=6228"
    D 2017-11-17 19:10:59.328 6228 BroadcastReceiver run socket closed.
    D 2017-11-17 19:10:59.831 6228 BroadcastSender sent #6 with 16 bytes "payload pid=6228"
    D 2017-11-17 19:11:00.333 6228 BroadcastSender sent #7 with 16 bytes "payload pid=6228"
    D 2017-11-17 19:11:00.834 6228 BroadcastSender sent #8 with 16 bytes "payload pid=6228"
    D 2017-11-17 19:11:01.336 6228 BroadcastSender sent #9 with 16 bytes "payload pid=6228"
    D 2017-11-17 19:11:01.839 6228 BroadcastSender sent #10 with 16 bytes "payload pid=6228"
    D 2017-11-17 19:11:02.341 6228 BroadcastSender sent #11 with 16 bytes "payload pid=6228"
    D 2017-11-17 19:11:02.844 6228 BroadcastSender sent #12 with 16 bytes "payload pid=6228"
    D 2017-11-17 19:11:03.346 6228 BroadcastSender sent #13 with 16 bytes "payload pid=6228"
    D 2017-11-17 19:11:01.810 6228 BroadcastSender unit test results=true
     */
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-16
      • 1970-01-01
      • 2014-10-22
      相关资源
      最近更新 更多