使用网络服务发现在 Java 服务器和 Android 客户端之间进行通信

Pre*_*sen 5 java android client-server jmdns dns-sd

我正在构建一个 Java 服务器应用程序(在 PC 上运行),该应用程序使用JmDNS将自身注册到本地网络,以及一个应该使用Network Service Discovery发现 java 服务器的 Android 客户端应用程序。
\n当我先运行android应用程序,然后运行java服务器时,应用程序成功发现注册的java服务器。
\n但是,当我第一次运行服务器,然后运行 ​​Android 应用程序时,onDiscoveryStarted调用了该方法,但该onServiceFound方法从未触发 - Android 应用程序没有发现服务器。\n这在我看来是一个意想不到的行为。

\n\n

成功案例
\nAndroid应用程序日志:
\n08-24 22:42:06.157 NSD_DISCOVER onCreate
\n08-24 22:42:06.373 NSD_DISCOVER\xef\xb9\x95 onDiscoveryStarted 服务发现已启动
\n08-24 22:42:30.256 NSD_DISCOVER\ xef\xb9\x95 onServiceFound 已知服务类型:_http._tcp。
\n08-24 22:42:30.293 NSD_DISCOVER\xef\xb9\x95 onServiceResolved 解决成功。名称:NsdApp,类型:._http._tcp,主机:/10.0.0.2,端口:52288

\n\n

Java 服务器日志:
\nSTART
\n已注册
\nEND
\nWAITING_FOR_MESSAGE
\nhello world
\nEND_THREAD

\n\n

失败案例

\n\n

Android 应用程序日志:
\n08-24 22:05:21.690 NSD_DISCOVER\xef\xb9\x95 onCreate
\n08-24 22:05:21.908 NSD_DISCOVER\xef\xb9\x95 onDiscoveryStarted 服务发现已启动

\n\n

Java 服务器日志:
\nSTART
\n已注册
\nEND
\nWAITING_FOR_MESSAGE

\n\n

服务器代码

\n\n
public class Server {\n\n    public static String mServiceName = "NsdApp";\n    public static final String SERVICE_TYPE = "_http._tcp.local";\n\n    static ServerSocket mServerSocket;\n\n\n    public static void main(String[] args) throws IOException {\n\n        System.out.println("START");\n\n    try {\n        mServerSocket = new ServerSocket(0);\n    } catch (IOException e) {\n        System.out.println("ServerSocket(0) FAILED");\n    }\n\n    int mPort = mServerSocket.getLocalPort();\n\n    JmDNS jmdns = JmDNS.create();\n    ServiceInfo info = ServiceInfo.create(SERVICE_TYPE, mServiceName, mPort, "B");\n    jmdns.registerService(info);\n\n    System.out.println("REGISTERED");\n\n    jmdns.close();\n\n    Thread mReceiveMessage = new Thread(new ReceiveMessage());\n    mReceiveMessage.start();\n\n    System.out.println("END");\n}\n\npublic static class ReceiveMessage implements Runnable {\n\n    public void run() {\n        System.out.println("WAITING_FOR_MESSAGE");\n        try {\n\n            Socket clientSocket = mServerSocket.accept(); \n            InputStreamReader inputStreamReader = new InputStreamReader(clientSocket.getInputStream());\n            BufferedReader bufferedReader = new BufferedReader(inputStreamReader); \n            String message = bufferedReader.readLine();\n            System.out.println(message);\n\n            bufferedReader.close();\n            inputStreamReader.close();\n            clientSocket.close();\n            System.out.println("END_THREAD");\n\n        } catch (IOException ex) {\n            System.out.println("Problem in message reading");\n        }\n    }\n}\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

客户端代码

\n\n
public class MainActivity extends Activity {\n\npublic static final String TAG = "NSD_DISCOVER";\npublic static final String SERVICE_TYPE = "_http._tcp.";\nNsdManager.DiscoveryListener mDiscoveryListener;\nNsdManager.ResolveListener mResolveListener;\nNsdManager mNsdManager;\nint port;\nInetAddress host;\n\n\n@Override\nprotected void onCreate(Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n    setContentView(R.layout.activity_main);\n\n    Log.v(TAG, "onCreate");\n\n    mNsdManager = (NsdManager) getSystemService(Context.NSD_SERVICE);\n    initializeResolveListener();\n    initializeDiscoveryListener();\n    mNsdManager.discoverServices(SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, mDiscoveryListener);\n}\n\n\npublic void initializeDiscoveryListener() {\n    mDiscoveryListener = new NsdManager.DiscoveryListener() {\n\n        @Override\n        public void onDiscoveryStarted(String regType) {\n            Log.v(TAG, "onDiscoveryStarted Service discovery started");\n        }\n\n        @Override\n        public void onServiceFound(NsdServiceInfo service) {\n            if (!service.getServiceType().equals(SERVICE_TYPE)) {\n                Log.v(TAG, "onServiceFound Unknown Service Type: " + service.getServiceType());\n            } else {\n                Log.v(TAG, "onServiceFound Known Service Type: " + service.getServiceType());\n                mNsdManager.resolveService(service, mResolveListener);\n            }\n        }\n\n        @Override\n        public void onServiceLost(NsdServiceInfo service) {\n            Log.e(TAG, "service lost" + service);\n        }\n\n        @Override\n        public void onDiscoveryStopped(String serviceType) {\n            Log.i(TAG, "Discovery stopped: " + serviceType);\n        }\n\n        @Override\n        public void onStartDiscoveryFailed(String serviceType, int errorCode) {\n            Log.e(TAG, "Discovery failed: Error code:" + errorCode);\n            mNsdManager.stopServiceDiscovery(this);\n        }\n\n        @Override\n        public void onStopDiscoveryFailed(String serviceType, int errorCode) {\n            Log.e(TAG, "Discovery failed: Error code:" + errorCode);\n            mNsdManager.stopServiceDiscovery(this);\n        }\n    };\n}\n\n\npublic void initializeResolveListener() {\n    mResolveListener = new NsdManager.ResolveListener() {\n\n        @Override\n        public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {\n            Log.e(TAG, "onResolveFailed Resolve failed" + errorCode);\n        }\n\n        @Override\n        public void onServiceResolved(NsdServiceInfo serviceInfo) {\n            Log.v(TAG, "onServiceResolved Resolve Succeeded. " + serviceInfo);\n            port = serviceInfo.getPort();\n            host = serviceInfo.getHost();\n\n            SendMessage sendMessageTask = new SendMessage();\n            sendMessageTask.execute();\n        }\n    };\n}\n\n\nprivate class SendMessage extends AsyncTask<Void, Void, Void> {\n\n    @Override\n    protected Void doInBackground(Void... params) {\n        try {\n\n            Socket client;\n            PrintWriter printwriter;\n\n            client = new Socket(host, port); \n            printwriter = new PrintWriter(client.getOutputStream(), true);\n            printwriter.write("hello world"); \n\n            printwriter.flush();\n            printwriter.close();\n            client.close(); \n\n        } catch (UnknownHostException e) {\n            e.printStackTrace();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n        return null;\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

}

\n

iag*_*een 4

jmdns.close()您注册后立即致电。只有当您打开 jmdns 时,您的服务才能被发现。您应该删除对 的调用close,使您的jmdns变量成为您的类的成员,然后仅当您不希望您的服务再被发现时才调用 close 。另外,在关闭 jmdns 之前调用也是一种很好的形式unregisterAllServices()