নেটওয়ার্ক পরিষেবা আবিষ্কার (NSD) আপনার অ্যাপকে পরিষেবাগুলিতে অ্যাক্সেস দেয় যা অন্য ডিভাইসগুলি স্থানীয় নেটওয়ার্কে সরবরাহ করে। NSD সমর্থন করে এমন ডিভাইসগুলির মধ্যে রয়েছে প্রিন্টার, ওয়েবক্যাম, HTTPS সার্ভার এবং অন্যান্য মোবাইল ডিভাইস।
এনএসডি ডিএনএস-ভিত্তিক পরিষেবা আবিষ্কার (ডিএনএস-এসডি) পদ্ধতি প্রয়োগ করে, যা আপনার অ্যাপকে পরিষেবার একটি প্রকার এবং পছন্দসই ধরনের পরিষেবা প্রদান করে এমন একটি ডিভাইসের উদাহরণের নাম উল্লেখ করে পরিষেবার অনুরোধ করতে দেয়৷ DNS-SD অ্যান্ড্রয়েড এবং অন্যান্য মোবাইল প্ল্যাটফর্মে সমর্থিত।
আপনার অ্যাপে এনএসডি যোগ করলে আপনার ব্যবহারকারীদের স্থানীয় নেটওয়ার্কে অন্যান্য ডিভাইস শনাক্ত করতে দেয় যা আপনার অ্যাপের অনুরোধগুলিকে সমর্থন করে। ফাইল শেয়ারিং বা মাল্টি-প্লেয়ার গেমিংয়ের মতো বিভিন্ন পিয়ার-টু-পিয়ার অ্যাপ্লিকেশনের জন্য এটি কার্যকর। অ্যান্ড্রয়েডের এনএসডি এপিআইগুলি এই ধরনের বৈশিষ্ট্যগুলি বাস্তবায়নের জন্য আপনার প্রয়োজনীয় প্রচেষ্টাকে সহজ করে তোলে৷
এই পাঠটি আপনাকে দেখায় কিভাবে একটি অ্যাপ্লিকেশন তৈরি করতে হয় যা স্থানীয় নেটওয়ার্কে এর নাম এবং সংযোগের তথ্য সম্প্রচার করতে পারে এবং একই কাজ করা অন্যান্য অ্যাপ্লিকেশন থেকে তথ্যের জন্য স্ক্যান করতে পারে। অবশেষে, এই পাঠ আপনাকে দেখায় কিভাবে অন্য ডিভাইসে চলমান একই অ্যাপ্লিকেশনের সাথে সংযোগ করতে হয়।
নেটওয়ার্কে আপনার পরিষেবা নিবন্ধন করুন
দ্রষ্টব্য: এই পদক্ষেপটি ঐচ্ছিক। আপনি যদি স্থানীয় নেটওয়ার্কে আপনার অ্যাপের পরিষেবাগুলি সম্প্রচার করার বিষয়ে চিন্তা না করেন, আপনি পরবর্তী বিভাগে যেতে পারেন, নেটওয়ার্কে পরিষেবাগুলি আবিষ্কার করুন ৷
স্থানীয় নেটওয়ার্কে আপনার পরিষেবা নিবন্ধন করতে, প্রথমে একটি NsdServiceInfo
অবজেক্ট তৈরি করুন। এই অবজেক্টটি সেই তথ্য প্রদান করে যা নেটওয়ার্কের অন্যান্য ডিভাইসগুলি ব্যবহার করে যখন তারা সিদ্ধান্ত নেয় যে তারা আপনার পরিষেবার সাথে সংযোগ করবে কিনা৷
কোটলিন
fun registerService(port: Int) { // Create the NsdServiceInfo object, and populate it. val serviceInfo = NsdServiceInfo().apply { // The name is subject to change based on conflicts // with other services advertised on the same network. serviceName = "NsdChat" serviceType = "_nsdchat._tcp" setPort(port) ... } }
জাভা
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("_nsdchat._tcp"); serviceInfo.setPort(port); ... }
এই কোড স্নিপেটটি "NsdChat" এ পরিষেবার নাম সেট করে। পরিষেবার নামটি উদাহরণের নাম: এটি নেটওয়ার্কের অন্যান্য ডিভাইসের দৃশ্যমান নাম। স্থানীয় পরিষেবাগুলি সন্ধান করতে NSD ব্যবহার করে নেটওয়ার্কের যে কোনও ডিভাইসে নামটি দৃশ্যমান। মনে রাখবেন যে নেটওয়ার্কে যেকোনো পরিষেবার জন্য নামটি অবশ্যই অনন্য হতে হবে এবং Android স্বয়ংক্রিয়ভাবে দ্বন্দ্ব সমাধান পরিচালনা করে। যদি নেটওয়ার্কের দুটি ডিভাইসে NsdChat অ্যাপ্লিকেশন ইনস্টল করা থাকে, তাদের মধ্যে একটি স্বয়ংক্রিয়ভাবে পরিষেবার নাম পরিবর্তন করে, যেমন "NsdChat (1)"।
দ্বিতীয় প্যারামিটারটি পরিষেবার ধরন সেট করে, অ্যাপ্লিকেশনটি কোন প্রোটোকল এবং পরিবহন স্তরটি ব্যবহার করে তা নির্দিষ্ট করে। সিনট্যাক্স হল "_<protocol>._<transportlayer>"। কোড স্নিপেটে, পরিষেবাটি টিসিপি-তে চলমান HTTP প্রোটোকল ব্যবহার করে। একটি প্রিন্টার পরিষেবা প্রদানকারী একটি অ্যাপ্লিকেশন (উদাহরণস্বরূপ, একটি নেটওয়ার্ক প্রিন্টার) পরিষেবার ধরনটি "_ipp._tcp" এ সেট করবে৷
দ্রষ্টব্য: ইন্টারন্যাশনাল অ্যাসাইনড নম্বর অথরিটি (IANA) NSD এবং Bonjour-এর মতো পরিষেবা আবিষ্কার প্রোটোকল দ্বারা ব্যবহৃত পরিষেবার প্রকারের একটি কেন্দ্রীভূত, অনুমোদিত তালিকা পরিচালনা করে। আপনি পরিষেবার নাম এবং পোর্ট নম্বরগুলির IANA তালিকা থেকে তালিকাটি ডাউনলোড করতে পারেন। আপনি যদি একটি নতুন পরিষেবার ধরন ব্যবহার করতে চান, তাহলে আপনার IANA পোর্টস এবং পরিষেবা নিবন্ধন ফর্মটি পূরণ করে এটি সংরক্ষণ করা উচিত৷
আপনার পরিষেবার জন্য পোর্ট সেট করার সময়, এটিকে হার্ডকোডিং এড়িয়ে চলুন কারণ এটি অন্যান্য অ্যাপ্লিকেশনের সাথে বিরোধপূর্ণ। উদাহরণস্বরূপ, ধরে নিই যে আপনার অ্যাপ্লিকেশন সর্বদা পোর্ট 1337 ব্যবহার করে এটি একই পোর্ট ব্যবহার করে এমন অন্যান্য ইনস্টল করা অ্যাপ্লিকেশনগুলির সাথে সম্ভাব্য বিরোধে রাখে। পরিবর্তে, ডিভাইসের পরবর্তী উপলব্ধ পোর্ট ব্যবহার করুন। যেহেতু এই তথ্যটি একটি পরিষেবা সম্প্রচারের মাধ্যমে অন্যান্য অ্যাপে সরবরাহ করা হয়, তাই আপনার অ্যাপ্লিকেশনটি যে পোর্ট ব্যবহার করে তা কম্পাইল-টাইমে অন্যান্য অ্যাপ্লিকেশন দ্বারা জানার প্রয়োজন নেই৷ পরিবর্তে, অ্যাপ্লিকেশনগুলি আপনার পরিষেবার সাথে সংযোগ করার ঠিক আগে আপনার পরিষেবা সম্প্রচার থেকে এই তথ্য পেতে পারে৷
আপনি যদি সকেটের সাথে কাজ করে থাকেন, তাহলে এখানে আপনি যেকোন উপলব্ধ পোর্টে একটি সকেটকে 0 তে সেট করে শুরু করতে পারেন।
কোটলিন
fun initializeServerSocket() { // Initialize a server socket on the next available port. serverSocket = ServerSocket(0).also { socket -> // Store the chosen port. mLocalPort = socket.localPort ... } }
জাভা
public void initializeServerSocket() { // Initialize a server socket on the next available port. serverSocket = new ServerSocket(0); // Store the chosen port. localPort = serverSocket.getLocalPort(); ... }
এখন আপনি NsdServiceInfo
অবজেক্টটি সংজ্ঞায়িত করেছেন, আপনাকে RegistrationListener
ইন্টারফেসটি বাস্তবায়ন করতে হবে। এই ইন্টারফেসটিতে Android দ্বারা ব্যবহৃত কলব্যাকগুলি রয়েছে যা পরিষেবা নিবন্ধন এবং নিবন্ধনমুক্তকরণের সাফল্য বা ব্যর্থতার বিষয়ে আপনার অ্যাপ্লিকেশনকে সতর্ক করতে।
কোটলিন
private val registrationListener = object : NsdManager.RegistrationListener { override fun 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.serviceName } override fun onRegistrationFailed(serviceInfo: NsdServiceInfo, errorCode: Int) { // Registration failed! Put debugging code here to determine why. } override fun onServiceUnregistered(arg0: NsdServiceInfo) { // Service has been unregistered. This only happens when you call // NsdManager.unregisterService() and pass in this listener. } override fun onUnregistrationFailed(serviceInfo: NsdServiceInfo, errorCode: Int) { // Unregistration failed. Put debugging code here to determine why. } }
জাভা
public void initializeRegistrationListener() { registrationListener = 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. serviceName = 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()
কল করুন।
মনে রাখবেন যে এই পদ্ধতিটি অ্যাসিঙ্ক্রোনাস, তাই পরিষেবাটি নিবন্ধিত হওয়ার পরে চালানোর জন্য যেকোন কোড অবশ্যই onServiceRegistered()
পদ্ধতিতে যেতে হবে।
কোটলিন
fun registerService(port: Int) { // Create the NsdServiceInfo object, and populate it. val serviceInfo = NsdServiceInfo().apply { // The name is subject to change based on conflicts // with other services advertised on the same network. serviceName = "NsdChat" serviceType = "_nsdchat._tcp" setPort(port) } nsdManager = (getSystemService(Context.NSD_SERVICE) as NsdManager).apply { registerService(serviceInfo, NsdManager.PROTOCOL_DNS_SD, registrationListener) } }
জাভা
public void registerService(int port) { NsdServiceInfo serviceInfo = new NsdServiceInfo(); serviceInfo.setServiceName("NsdChat"); serviceInfo.setServiceType("_http._tcp."); serviceInfo.setPort(port); nsdManager = Context.getSystemService(Context.NSD_SERVICE); nsdManager.registerService( serviceInfo, NsdManager.PROTOCOL_DNS_SD, registrationListener); }
নেটওয়ার্কে পরিষেবাগুলি আবিষ্কার করুন
নেটওয়ার্কটি জীবনের সাথে মিশে যাচ্ছে, বিস্টলি নেটওয়ার্ক প্রিন্টার থেকে শুরু করে নমনীয় নেটওয়ার্ক ওয়েবক্যাম পর্যন্ত, কাছাকাছি টিক-ট্যাক-টো প্লেয়ারদের নৃশংস, জ্বলন্ত যুদ্ধ পর্যন্ত। আপনার অ্যাপ্লিকেশনটিকে কার্যকারিতার এই প্রাণবন্ত ইকোসিস্টেমটি দেখতে দেওয়ার চাবিকাঠি হল পরিষেবা আবিষ্কার। আপনার অ্যাপ্লিকেশনটিকে নেটওয়ার্কে পরিষেবা সম্প্রচার শুনতে হবে কোন পরিষেবাগুলি উপলব্ধ তা দেখতে এবং অ্যাপ্লিকেশনটি কাজ করতে পারে না এমন কিছু ফিল্টার আউট করতে হবে৷
পরিষেবা রেজিস্ট্রেশনের মতো পরিষেবা আবিষ্কারের দুটি ধাপ রয়েছে: প্রাসঙ্গিক কলব্যাকগুলির সাথে একটি আবিষ্কার শ্রোতা সেট আপ করা এবং discoverServices()
এ একটি একক অ্যাসিঙ্ক্রোনাস API কল করা।
প্রথমে, NsdManager.DiscoveryListener
প্রয়োগ করে এমন একটি বেনামী ক্লাস ইনস্ট্যান্ট করুন। নিম্নলিখিত স্নিপেট একটি সহজ উদাহরণ দেখায়:
কোটলিন
// Instantiate a new DiscoveryListener private val discoveryListener = object : NsdManager.DiscoveryListener { // Called as soon as service discovery begins. override fun onDiscoveryStarted(regType: String) { Log.d(TAG, "Service discovery started") } override fun onServiceFound(service: NsdServiceInfo) { // A service was found! Do something with it. Log.d(TAG, "Service discovery success$service") when { service.serviceType != SERVICE_TYPE -> // Service type is the string containing the protocol and // transport layer for this service. Log.d(TAG, "Unknown Service Type: ${service.serviceType}") service.serviceName == 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") service.serviceName.contains("NsdChat") -> nsdManager.resolveService(service, resolveListener) } } override fun onServiceLost(service: NsdServiceInfo) { // When the network service is no longer available. // Internal bookkeeping code goes here. Log.e(TAG, "service lost: $service") } override fun onDiscoveryStopped(serviceType: String) { Log.i(TAG, "Discovery stopped: $serviceType") } override fun onStartDiscoveryFailed(serviceType: String, errorCode: Int) { Log.e(TAG, "Discovery failed: Error code:$errorCode") nsdManager.stopServiceDiscovery(this) } override fun onStopDiscoveryFailed(serviceType: String, errorCode: Int) { Log.e(TAG, "Discovery failed: Error code:$errorCode") nsdManager.stopServiceDiscovery(this) } }
জাভা
public void initializeDiscoveryListener() { // Instantiate a new DiscoveryListener discoveryListener = 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(serviceName)) { // 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: " + serviceName); } else if (service.getServiceName().contains("NsdChat")){ nsdManager.resolveService(service, resolveListener); } } @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); nsdManager.stopServiceDiscovery(this); } @Override public void onStopDiscoveryFailed(String serviceType, int errorCode) { Log.e(TAG, "Discovery failed: Error code:" + errorCode); nsdManager.stopServiceDiscovery(this); } }; }
NSD API এই ইন্টারফেসের পদ্ধতিগুলি ব্যবহার করে আপনার অ্যাপ্লিকেশনকে জানাতে যখন আবিষ্কার শুরু হয়, কখন এটি ব্যর্থ হয় এবং কখন পরিষেবাগুলি খুঁজে পাওয়া যায় এবং হারিয়ে যায় (হারানো মানে "আর উপলব্ধ নেই")। লক্ষ্য করুন যে যখন একটি পরিষেবা পাওয়া যায় তখন এই স্নিপেটটি বেশ কয়েকটি পরীক্ষা করে।
- ডিভাইসটি কেবল তার নিজস্ব সম্প্রচার (যা বৈধ) তুলেছে কিনা তা নির্ধারণ করতে পাওয়া পরিষেবাটির পরিষেবার নাম স্থানীয় পরিষেবার পরিষেবার নামের সাথে তুলনা করা হয়৷
- পরিষেবার ধরনটি পরীক্ষা করা হয়েছে, এটি এমন একটি পরিষেবা যা আপনার অ্যাপ্লিকেশন সংযোগ করতে পারে তা যাচাই করতে৷
- সঠিক অ্যাপ্লিকেশনের সাথে সংযোগ যাচাই করতে পরিষেবার নামটি পরীক্ষা করা হয়েছে৷
পরিষেবার নাম চেক করা সবসময় প্রয়োজনীয় নয়, এবং আপনি যদি একটি নির্দিষ্ট অ্যাপ্লিকেশনের সাথে সংযোগ করতে চান তবেই এটি প্রাসঙ্গিক৷ উদাহরণস্বরূপ, অ্যাপ্লিকেশনটি শুধুমাত্র অন্যান্য ডিভাইসে চলার উদাহরণগুলির সাথে সংযোগ করতে চাইতে পারে। যাইহোক, যদি অ্যাপ্লিকেশনটি একটি নেটওয়ার্ক প্রিন্টারের সাথে সংযোগ করতে চায়, তবে এটি দেখতে যথেষ্ট যে পরিষেবার ধরনটি "_ipp._tcp"।
শ্রোতা সেট আপ করার পরে, discoverServices()
কে কল করুন, আপনার অ্যাপ্লিকেশনটি যে ধরনের পরিষেবার সন্ধান করা উচিত, ব্যবহার করার জন্য আবিষ্কার প্রোটোকল এবং আপনি এইমাত্র যে শ্রোতা তৈরি করেছেন তা পাস করে।
কোটলিন
nsdManager.discoverServices(SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, discoveryListener)
জাভা
nsdManager.discoverServices( SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, discoveryListener);
নেটওয়ার্কে পরিষেবাগুলির সাথে সংযোগ করুন৷
যখন আপনার অ্যাপ্লিকেশন নেটওয়ার্কে সংযোগ করার জন্য একটি পরিষেবা খুঁজে পায়, তখন এটিকে অবশ্যই প্রথমে resolveService()
পদ্ধতি ব্যবহার করে সেই পরিষেবার জন্য সংযোগের তথ্য নির্ধারণ করতে হবে। এই পদ্ধতিতে পাস করার জন্য একটি NsdManager.ResolveListener
প্রয়োগ করুন এবং সংযোগের তথ্য সম্বলিত NsdServiceInfo
পেতে এটি ব্যবহার করুন।
কোটলিন
private val resolveListener = object : NsdManager.ResolveListener { override fun onResolveFailed(serviceInfo: NsdServiceInfo, errorCode: Int) { // Called when the resolve fails. Use the error code to debug. Log.e(TAG, "Resolve failed: $errorCode") } override fun onServiceResolved(serviceInfo: NsdServiceInfo) { Log.e(TAG, "Resolve Succeeded. $serviceInfo") if (serviceInfo.serviceName == mServiceName) { Log.d(TAG, "Same IP.") return } mService = serviceInfo val port: Int = serviceInfo.port val host: InetAddress = serviceInfo.host } }
জাভা
public void initializeResolveListener() { resolveListener = 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(serviceName)) { Log.d(TAG, "Same IP."); return; } mService = serviceInfo; int port = mService.getPort(); InetAddress host = mService.getHost(); } }; }
একবার পরিষেবাটি সমাধান হয়ে গেলে, আপনার অ্যাপ্লিকেশনটি একটি IP ঠিকানা এবং পোর্ট নম্বর সহ বিশদ পরিষেবার তথ্য পায়৷ এই পরিষেবাতে আপনার নিজস্ব নেটওয়ার্ক সংযোগ তৈরি করতে আপনার যা প্রয়োজন।
আবেদন বন্ধ আপনার পরিষেবা নিবন্ধনমুক্ত
অ্যাপ্লিকেশানের লাইফ সাইকেলের সময় উপযুক্ত হিসাবে NSD কার্যকারিতা সক্ষম এবং নিষ্ক্রিয় করা গুরুত্বপূর্ণ। আপনার অ্যাপ্লিকেশানটি বন্ধ হয়ে গেলে নিবন্ধনমুক্ত করা অন্য অ্যাপ্লিকেশানগুলিকে এটি এখনও সক্রিয় ভাবতে এবং এটির সাথে সংযোগ করার চেষ্টা করতে বাধা দেয়৷ এছাড়াও, পরিষেবা আবিষ্কার একটি ব্যয়বহুল ক্রিয়াকলাপ, এবং যখন অভিভাবক কার্যকলাপ বিরতি দেওয়া হয় তখন বন্ধ করা উচিত এবং যখন কার্যকলাপ পুনরায় শুরু করা হয় তখন পুনরায় সক্ষম করা হয়৷ আপনার প্রধান ক্রিয়াকলাপের জীবনচক্র পদ্ধতিগুলিকে ওভাররাইড করুন এবং পরিষেবা সম্প্রচার শুরু এবং বন্ধ করার জন্য কোড সন্নিবেশ করুন এবং উপযুক্ত হিসাবে আবিষ্কার করুন৷
কোটলিন
// In your application's Activity override fun onPause() { nsdHelper?.tearDown() super.onPause() } override fun onResume() { super.onResume() nsdHelper?.apply { registerService(connection.localPort) discoverServices() } } override fun onDestroy() { nsdHelper?.tearDown() connection.tearDown() super.onDestroy() } // NsdHelper's tearDown method fun tearDown() { nsdManager.apply { unregisterService(registrationListener) stopServiceDiscovery(discoveryListener) } }
জাভা
// In your application's Activity @Override protected void onPause() { if (nsdHelper != null) { nsdHelper.tearDown(); } super.onPause(); } @Override protected void onResume() { super.onResume(); if (nsdHelper != null) { nsdHelper.registerService(connection.getLocalPort()); nsdHelper.discoverServices(); } } @Override protected void onDestroy() { nsdHelper.tearDown(); connection.tearDown(); super.onDestroy(); } // NsdHelper's tearDown method public void tearDown() { nsdManager.unregisterService(registrationListener); nsdManager.stopServiceDiscovery(discoveryListener); }