<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                > 編寫:[naizhengtan](https://github.com/naizhengtan) - 原文:[http://developer.android.com/training/connect-devices-wirelessly/nsd.html](http://developer.android.com/training/connect-devices-wirelessly/nsd.html) 添加網絡服務發現(Network Service Discovery)到你的app中可以使你的用戶辨識在局域網且支持你的app所請求的服務的設備。這種技術在端對端應用中能夠提供大量幫助,例如文件共享、聯機游戲等。Android提供了網絡服務發現(NSD)相應的API,大大降低了其實現難度。 本講將簡要介紹如何創建NSD應用,使其能夠在本地網絡內廣播自己的名稱和鏈接信息,并且掃描網絡發現其他NSD設備。最后,將介紹如何連接到運行著同樣應用的另一臺設備上。 ### 注冊NSD服務 > **Note:** 這一步驟是選做的。如果你并不關心自己的服務是否被廣播,你可以跳過這一步,直接嘗試[發現網絡中的服務](#)。 在局域網內注冊自己服務的第一步是創建[NsdServiceInfo](http://developer.android.com/reference/android/net/nsd/NsdServiceInfo.html)對象。此對象包含的信息能夠幫助其他設備決定是否要連接到你所提供的服務。 ~~~ public void registerService(int port) { // Create the NsdServiceInfo object, and populate it. NsdServiceInfo serviceInfo = new NsdServiceInfo(); // The name is subject to change based on conflicts // with other services advertised on the same network. serviceInfo.setServiceName("NsdChat"); serviceInfo.setServiceType("_http._tcp."); serviceInfo.setPort(port); .... } ~~~ 這段代碼將所提供的服務命名為“NsdChat”。該名稱將對所有局域網絡中的設備可見。需要注意的是,在網絡內該名稱必須是獨一無二的。Android系統會自動處理沖突的服務名稱。如果同時有兩個名為“NsdChat”的應用,其中一個會被自動轉換為“NsdChat(1)”。 第二個參數設置了服務類型,即,使用的通信協議和傳輸層協議,語法是“_< protocol >._< transportlayer >”。在上面的代碼中,服務使用了TCP協議上的HTTP協議。如果應用想要提供打印服務(例如,一臺網絡打印機)應該將服務的類型設置為“_ipp._tcp”。 > **Note:** 互聯網編號分配機構(International Assigned Numbers Authority,簡稱IANA)提供用于服務發現協議(例如NSD和Bonjour)的官方服務種類列表。你可以下載該列表了解相應的服務名稱和端口號碼。如果你想起用新的服務種類,應該向IANA官方提交申請。 當為你的服務設置端口號時,應該盡量避免將其硬編碼在代碼中,防止與其他應用產生沖突。例如,如果你的應用僅僅使用端口1337,就可能與其他使用1337端口的應用發生沖突。解決方法是,不要硬編碼,使用下一個可用的端口。不必擔心其他應用無法知曉服務的端口號,因為該信息將包含在服務的廣播包中。接收到廣播后,其他應用將從廣播包中得知服務端口號,并通過端口連接到你的服務上。 如果你使用的是socket,你可以將端口號初始值設置為0來使用下一個可用端口。 ~~~ public void initializeServerSocket() { // Initialize a server socket on the next available port. mServerSocket = new ServerSocket(0); // Store the chosen port. mLocalPort = mServerSocket.getLocalPort(); ... } ~~~ 現在,你已經成功的創建了[NsdServiceInfo](http://developer.android.com/reference/android/net/nsd/NsdServiceInfo.html)對象,接下來要做的是實現[RegistrationListener](http://developer.android.com/reference/android/net/nsd/NsdManager.RegistrationListener.html)接口。該接口包含了注冊在Android系統中的一系列回調函數,作用是通知應用程序服務注冊/注銷的成功和失敗。 ~~~ public void initializeRegistrationListener() { mRegistrationListener = new NsdManager.RegistrationListener() { @Override public void onServiceRegistered(NsdServiceInfo NsdServiceInfo) { // Save the service name. Android may have changed it in order to // resolve a conflict, so update the name you initially requested // with the name Android actually used. mServiceName = NsdServiceInfo.getServiceName(); } @Override public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode) { // Registration failed! Put debugging code here to determine why. } @Override public void onServiceUnregistered(NsdServiceInfo arg0) { // Service has been unregistered. This only happens when you call // NsdManager.unregisterService() and pass in this listener. } @Override public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode) { // Unregistration failed. Put debugging code here to determine why. } }; } ~~~ 萬事俱備只欠東風,調用[registerService()](http://developer.android.com/reference/android/net/nsd/NsdManager.html#registerService(android.net.nsd.NsdServiceInfo, int, android.net.nsd.NsdManager.RegistrationListener)方法,真正注冊服務。 因為該方法是異步的,所以在服務注冊之后的操作都需要在[onServiceRegistered()](http://developer.android.com/reference/android/net/nsd/NsdManager.RegistrationListener.html#onServiceRegistered(android.net.nsd.NsdServiceInfo))方法中進行。 ~~~ public void registerService(int port) { NsdServiceInfo serviceInfo = new NsdServiceInfo(); serviceInfo.setServiceName("NsdChat"); serviceInfo.setServiceType("_http._tcp."); serviceInfo.setPort(port); mNsdManager = Context.getSystemService(Context.NSD_SERVICE); mNsdManager.registerService( serviceInfo, NsdManager.PROTOCOL_DNS_SD, mRegistrationListener); } ~~~ ### 發現網絡中的服務 網絡充斥著我們的生活,從網絡打印機到網絡攝像頭,再到聯網井字棋。網絡服務發現是能讓你的應用融入這一切功能的關鍵。你的應用需要偵聽網絡內服務的廣播,發現可用的服務,過濾無效的信息。 與注冊網絡服務類似,服務發現需要兩步驟:正確配置發現監聽者(Discover Listener),以及調用[discoverServices()](http://developer.android.com/reference/android/net/nsd/NsdManager.html#discoverServices(java.lang.String, int, android.net.nsd.NsdManager.DiscoveryListener))這個異步API。 首先,實例化一個實現[NsdManager.DiscoveryListener](http://developer.android.com/reference/android/net/nsd/NsdManager.DiscoveryListener.html)接口的匿名類。下列代碼是一個簡單的范例: ~~~ public void initializeDiscoveryListener() { // Instantiate a new DiscoveryListener mDiscoveryListener = new NsdManager.DiscoveryListener() { // Called as soon as service discovery begins. @Override public void onDiscoveryStarted(String regType) { Log.d(TAG, "Service discovery started"); } @Override public void onServiceFound(NsdServiceInfo service) { // A service was found! Do something with it. Log.d(TAG, "Service discovery success" + service); if (!service.getServiceType().equals(SERVICE_TYPE)) { // Service type is the string containing the protocol and // transport layer for this service. Log.d(TAG, "Unknown Service Type: " + service.getServiceType()); } else if (service.getServiceName().equals(mServiceName)) { // The name of the service tells the user what they'd be // connecting to. It could be "Bob's Chat App". Log.d(TAG, "Same machine: " + mServiceName); } else if (service.getServiceName().contains("NsdChat")){ mNsdManager.resolveService(service, mResolveListener); } } @Override public void onServiceLost(NsdServiceInfo service) { // When the network service is no longer available. // Internal bookkeeping code goes here. Log.e(TAG, "service lost" + service); } @Override public void onDiscoveryStopped(String serviceType) { Log.i(TAG, "Discovery stopped: " + serviceType); } @Override public void onStartDiscoveryFailed(String serviceType, int errorCode) { Log.e(TAG, "Discovery failed: Error code:" + errorCode); mNsdManager.stopServiceDiscovery(this); } @Override public void onStopDiscoveryFailed(String serviceType, int errorCode) { Log.e(TAG, "Discovery failed: Error code:" + errorCode); mNsdManager.stopServiceDiscovery(this); } }; } ~~~ NSD API通過使用該接口中的方法通知用戶程序何時發現開始、何時發現失敗、何時找到可用服務、何時服務丟失(丟失意味著“不再可用”)。在上述代碼中,當發現了可用的服務時,程序做了幾次檢查。 1. 比較發現的服務名稱與本地的服務,判斷是否發現的是本機的服務(這是合法的)。 1. 檢查服務的類型,確認是否可以接入。 1. 檢查服務的名稱,確認接入了正確的應用。 我們并不需要每次都檢查服務名稱,僅當你想要接入特定的應用時,再去判斷。例如,應用只想與運行在其他設備上的相同應用通信。然而,如果應用僅僅想接入到一臺網絡打印機,那么看到服務類型是“_ipp._tcp”的服務就足夠了。 當配置好發現回調函數后,調用[discoverService()](http://developer.android.com/reference/android/net/nsd/NsdManager.html#discoverServices(java.lang.String, int, android.net.nsd.NsdManager.DiscoveryListener))函數,其參數包括試圖發現的服務種類、發現使用的協議、以及上一步創建的監聽者。 ~~~ mNsdManager.discoverServices( SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, mDiscoveryListener); ~~~ ### 連接到網絡上的服務 當你的代碼發現了網上可接入的服務,第一件必須做的事情是確認服務的連接信息。調用[resolveService()](http://developer.android.com/reference/android/net/nsd/NsdManager.html#resolveService(android.net.nsd.NsdServiceInfo, android.net.nsd.NsdManager.ResolveListener))方法,并將實現了[NsdManager.ResolveListener](http://developer.android.com/reference/android/net/nsd/NsdManager.ResolveListener.html)的對象和在[服務發現](#)過程中得到的[NsdSerServiceInfo](http://developer.android.com/reference/android/net/nsd/NsdServiceInfo.html)對象傳入。通過該方法,可以將連接信息從[NsdSerServiceInfo](http://developer.android.com/reference/android/net/nsd/NsdServiceInfo.html)對象中解析出來。 ~~~ public void initializeResolveListener() { mResolveListener = new NsdManager.ResolveListener() { @Override public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) { // Called when the resolve fails. Use the error code to debug. Log.e(TAG, "Resolve failed" + errorCode); } @Override public void onServiceResolved(NsdServiceInfo serviceInfo) { Log.e(TAG, "Resolve Succeeded. " + serviceInfo); if (serviceInfo.getServiceName().equals(mServiceName)) { Log.d(TAG, "Same IP."); return; } mService = serviceInfo; int port = mService.getPort(); InetAddress host = mService.getHost(); } }; } ~~~ 當服務解析完成后,你將獲得服務的詳細資料,包括其IP地址和端口號。此時,你有了服務的地址和端口,可以通過創建自己網絡連接與服務進行通訊。 ### 當程序退出時注銷服務 在應用的生命周期中正確的開啟和關閉NSD服務是十分關鍵的。在程序退出時注銷服務可以防止其他程序因為不知道服務退出而反復嘗試連接的行為。另外,服務發現是一種開銷很大的操作,應該隨著父[Activity](# "An activity represents a single screen with a user interface.")的暫停而停止,當用戶返回該界面是再開啟。因此,開發者應該重載[Activity](# "An activity represents a single screen with a user interface.")的生命周期函數,并正確操作服務的廣播和發現。 ~~~ //In your application's Activity @Override protected void onPause() { if (mNsdHelper != null) { mNsdHelper.tearDown(); } super.onPause(); } @Override protected void onResume() { super.onResume(); if (mNsdHelper != null) { mNsdHelper.registerService(mConnection.getLocalPort()); mNsdHelper.discoverServices(); } } @Override protected void onDestroy() { mNsdHelper.tearDown(); mConnection.tearDown(); super.onDestroy(); } // NsdHelper's tearDown method public void tearDown() { mNsdManager.unregisterService(mRegistrationListener); mNsdManager.stopServiceDiscovery(mDiscoveryListener); } ~~~
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看