背景:
当你使用NsdManager发现多个服务并尝试解析IP和端口时,只能解析一个服务。
可能原因:
- 竞争条件:如果你尝试同时解析多个服务,可能会出现竞争条件,导致只有一个解析成功。
- 服务解析限制:
NsdManager可能在某一时刻只允许解析一个服务。 - 回调覆盖:如果你使用了同一个
ResolveListener实例解析多个服务,可能会导致回调被覆盖,从而只处理最后一个解析的服务。
尝试方法:
-
1. 确保每个服务使用单独的
ResolveListener实例: 每个服务解析请求应该有自己独立的ResolveListener实例。 -
2. 逐一解析服务: 避免同时解析多个服务,而是一个接一个地解析,确保上一个解析完成后再开始下一个。
改动前的代码:
import android.content.Context;
import android.net.nsd.NsdManager;
import android.net.nsd.NsdServiceInfo;
import android.util.Log;
import androidx.annotation.NonNull;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
public class NsdHelper {
private static final String TAG = "NsdHelper";
private NsdManager nsdManager;
private NsdManager.ResolveListener resolveListener;
public NsdHelper(Context context) {
nsdManager = (NsdManager) context.getSystemService(Context.NSD_SERVICE);
}
public void resolveService(@NonNull NsdServiceInfo serviceInfo) {
Executor executor = Executors.newSingleThreadExecutor();
resolveListener = new NsdManager.ResolveListener() {
@Override
public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
Log.e(TAG, "Resolve failed: " + errorCode);
}
@Override
public void onServiceResolved(NsdServiceInfo serviceInfo) {
Log.i(TAG, "Service resolved: " + serviceInfo);
// Here you can get the resolved service details
String host = serviceInfo.getHost().getHostAddress();
int port = serviceInfo.getPort();
Log.i(TAG, "Host: " + host + ", Port: " + port);
}
};
nsdManager.resolveService(serviceInfo, executor, resolveListener);
}
}
改动后的代码:
以下是改进后的Kotlin代码示例,展示了如何处理多个服务的解析:
import android.content.Context
import android.net.nsd.NsdManager
import android.net.nsd.NsdServiceInfo
import android.util.Log
import java.util.concurrent.Executors
class NsdHelper(context: Context) {
private val nsdManager: NsdManager = context.getSystemService(Context.NSD_SERVICE) as NsdManager
private val executor = Executors.newSingleThreadExecutor()
private val serviceQueue = mutableListOf()
fun discoverServices() {
val discoveryListener = object : NsdManager.DiscoveryListener {
override fun onDiscoveryStarted(serviceType: String) {
Log.i(TAG, "Service discovery started")
}
override fun onServiceFound(serviceInfo: NsdServiceInfo) {
Log.i(TAG, "Service found: $serviceInfo")
// 将发现的服务添加到队列中等待解析
serviceQueue.add(serviceInfo)
if (serviceQueue.size == 1) {
resolveNextService()
}
}
override fun onServiceLost(serviceInfo: NsdServiceInfo) {
Log.e(TAG, "Service lost: $serviceInfo")
serviceQueue.remove(serviceInfo)
}
override fun onDiscoveryStopped(serviceType: String) {
Log.i(TAG, "Service discovery stopped")
}
override fun onStartDiscoveryFailed(serviceType: String, errorCode: Int) {
Log.e(TAG, "Service discovery start failed: $errorCode")
nsdManager.stopServiceDiscovery(this)
}
override fun onStopDiscoveryFailed(serviceType: String, errorCode: Int) {
Log.e(TAG, "Service discovery stop failed: $errorCode")
nsdManager.stopServiceDiscovery(this)
}
}
nsdManager.discoverServices("_http._tcp.", NsdManager.PROTOCOL_DNS_SD, discoveryListener)
}
private fun resolveNextService() {
if (serviceQueue.isEmpty()) return
val serviceInfo = serviceQueue.first()
val resolveListener = object : NsdManager.ResolveListener {
override fun onResolveFailed(serviceInfo: NsdServiceInfo, errorCode: Int) {
Log.e(TAG, "Resolve failed: $errorCode")
serviceQueue.remove(serviceInfo)
resolveNextService()
}
override fun onServiceResolved(serviceInfo: NsdServiceInfo) {
Log.i(TAG, "Service resolved: host, Port: $port")
serviceQueue.remove(serviceInfo)
resolveNextService()
}
}
nsdManager.resolveService(serviceInfo, executor, resolveListener)
}
companion object {
private const val TAG = "NsdHelper"
}
}
代码解释:
- 服务队列:使用一个
MutableList来保存发现的服务。 - 发现服务:通过
discoverServices方法启动服务发现。 - 解析服务:在
onServiceFound回调中,将发现的服务添加到队列中,并调用resolveNextService方法开始解析。 - 逐一解析:
resolveNextService方法从队列中取出第一个服务进行解析,并在解析完成或失败后解析下一个服务。
以上方式确保每次只解析一个服务,从而避免竞争条件和回调覆盖的问题。