Mdns 扫描这么用?
NsdManager、NsdServiceInfo
NsdManager:The Network Service Discovery Manager
NsdServiceInfo
package moe.shizuku.manager.adb
//import androidx.lifecycle.MutableLiveData
import android.content.Context
import android.net.nsd.NsdManager
import android.net.nsd.NsdServiceInfo
import android.os.Build
import android.util.Log
import androidx.annotation.RequiresApi
import java.io.IOException
import java.net.InetAddress
import java.net.InetSocketAddress
import java.net.ServerSocket
@RequiresApi(Build.VERSION_CODES.R)
class AdbMdns(
context: Context, private val serviceType: String,
private val port: PortListener
) {
private var registered = false
var running = false
private var serviceName: String? = null
private val listener: DiscoveryListener
private val nsdManager: NsdManager = context.getSystemService(NsdManager::class.java)
var serviceType= "_http._tcp" //打印机_ipp._tcp
fun start() {
running = true
if (!registered) {
nsdManager.discoverServices(serviceType, NsdManager.PROTOCOL_DNS_SD, listener)
}
}
fun stop() {
running = false
if (registered) {
nsdManager.stopServiceDiscovery(listener)
}
}
private fun onDiscoveryStart() {
registered = true
}
private fun onDiscoveryStop() {
registered = false
}
private fun onServiceFound(info: NsdServiceInfo) {
nsdManager.resolveService(info, ResolveListener(this))
}
private fun onServiceLost(info: NsdServiceInfo) {
if (info.serviceName == serviceName)
port.postValue(info.host, -1, false)
}
private fun onStartDiscoveryFailed(str: String,i: Int){
Log.e("my_tag", "onStartDiscoveryFailed :$str :$i")
} private fun onResolveFailed(resolvedService: NsdServiceInfo,i: Int){
Log.e("my_tag", "onResolveFailed :$resolvedService :$i")
}
private fun onServiceResolved(resolvedService: NsdServiceInfo) {
Log.e("my_tag", "resolvedService:$resolvedService")
//todo 11.2 3:17
port.postValue(
resolvedService.host,
resolvedService.port,
isPortAvailable(resolvedService.port)
)
}
private fun isPortAvailable(port: Int) = try {
ServerSocket().use {
it.bind(InetSocketAddress(getAddress(), port), 1)//10.19
false
}
} catch (e: IOException) {
true
}
internal class DiscoveryListener(private val adbMdns: AdbMdns) : NsdManager.DiscoveryListener {
override fun onDiscoveryStarted(str: String) {
adbMdns.onDiscoveryStart()
}
override fun onStartDiscoveryFailed(str: String, i: Int) {
adbMdns.onStartDiscoveryFailed(str,i)
}
override fun onDiscoveryStopped(str: String) {
adbMdns.onDiscoveryStop()
}
override fun onStopDiscoveryFailed(str: String, i: Int) {}
override fun onServiceFound(nsdServiceInfo: NsdServiceInfo) {
adbMdns.onServiceFound(nsdServiceInfo)
}
override fun onServiceLost(nsdServiceInfo: NsdServiceInfo) {
adbMdns.onServiceLost(nsdServiceInfo)
}
}
internal class ResolveListener(private val adbMdns: AdbMdns) : NsdManager.ResolveListener {
override fun onResolveFailed(nsdServiceInfo: NsdServiceInfo, i: Int) {
adbMdns.onResolveFailed(nsdServiceInfo,i)
}
override fun onServiceResolved(nsdServiceInfo: NsdServiceInfo) {
adbMdns.onServiceResolved(nsdServiceInfo)
}
}
init {
listener = DiscoveryListener(this)
}
}
NsdManager 构造方法
/**
290 * Create a new Nsd instance. Applications use
291 * { @link android.content.Context#getSystemService Context.getSystemService()} to retrieve
292 * { @link android.content.Context#NSD_SERVICE Context.NSD_SERVICE}.
293 * @param service the Binder interface
294 * @hide - hide this because it takes in a parameter of type INsdManager, which
295 * is a system private class.
296 */
297 public NsdManager(Context context, INsdManager service) {
298 mService = service;
299 mContext = context;
300 init();
301 }
init()
/**
507 * Initialize AsyncChannel
508 */
509 private void init() {
510 final Messenger messenger = getMessenger();
511 if (messenger == null) {
512 fatal("Failed to obtain service Messenger");
513 }
514 HandlerThread t = new HandlerThread("NsdManager");
515 t.start();
516 mHandler = new ServiceHandler(t.getLooper());
517 mAsyncChannel.connect(mContext, mHandler, messenger);
518 try {
519 mConnected.await();
520 } catch (InterruptedException e) {
521 fatal("Interrupted wait at init");
522 }
523 if (CompatChanges.isChangeEnabled(RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)) {
524 return;
525 }
526 // Only proactively start the daemon if the target SDK < S, otherwise the internal service
527 // would automatically start/stop the native daemon as needed.
528 mAsyncChannel.sendMessage(DAEMON_STARTUP);
529 }
nsdManager.discoverServices(serviceType, NsdManager.PROTOCOL_DNS_SD, listener)
onServiceFound回调里nsdManager.resolveService(info, ResolveListener(this))
private fun onServiceFound(info: NsdServiceInfo) {
nsdManager.resolveService(info, ResolveListener(this))
}
再回调onServiceResolved(NsdServiceInfo nsdServiceInfo)
resolvedService.host, resolvedService.port,
建立tcp socket 连接是否能可用
private fun isPortAvailable(port: Int) = try {
ServerSocket().use { it.bind(InetSocketAddress(getAddress(), port), 1)
//10.19 false }
} catch (e: IOException) { true }
// 解析成功,可以建立连接
InetAddress inetAddress = serviceInfo.getHost();
int port = serviceInfo.getPort();
try {
Socket socket = new Socket(inetAddress.getHostAddress(), port);
// 连接建立后的逻辑处理
} catch (IOException e) {
e.printStackTrace();
// 处理连接异常
}