ব্লুটুথ ডিভাইস সংযুক্ত করুন

দুটি ডিভাইসের মধ্যে একটি সংযোগ তৈরি করতে, আপনাকে অবশ্যই সার্ভার-সাইড এবং ক্লায়েন্ট-সাইড প্রক্রিয়া উভয়ই প্রয়োগ করতে হবে কারণ একটি ডিভাইসকে অবশ্যই একটি সার্ভার সকেট খুলতে হবে এবং অন্যটিকে সার্ভার ডিভাইসের MAC ঠিকানা ব্যবহার করে সংযোগ শুরু করতে হবে। সার্ভার ডিভাইস এবং ক্লায়েন্ট ডিভাইস প্রতিটি প্রয়োজনীয় BluetoothSocket বিভিন্ন উপায়ে পায়। একটি ইনকামিং সংযোগ গ্রহণ করা হলে সার্ভার সকেট তথ্য গ্রহণ করে। ক্লায়েন্ট সকেট তথ্য প্রদান করে যখন এটি সার্ভারে একটি RFCOMM চ্যানেল খোলে।

সার্ভার এবং ক্লায়েন্ট একে অপরের সাথে সংযুক্ত বলে বিবেচিত হয় যখন তাদের প্রত্যেকের একই RFCOMM চ্যানেলে একটি সংযুক্ত BluetoothSocket থাকে। এই মুহুর্তে, প্রতিটি ডিভাইস ইনপুট এবং আউটপুট স্ট্রীম পেতে পারে এবং ডেটা স্থানান্তর শুরু হতে পারে, যা ব্লুটুথ ডেটা স্থানান্তর সম্পর্কে বিভাগে আলোচনা করা হয়েছে। এই বিভাগটি বর্ণনা করে কিভাবে দুটি ডিভাইসের মধ্যে সংযোগ শুরু করতে হয়।

ব্লুটুথ ডিভাইস খোঁজার চেষ্টা করার আগে আপনার উপযুক্ত ব্লুটুথ অনুমতি আছে এবং ব্লুটুথের জন্য আপনার অ্যাপ সেট আপ করুন তা নিশ্চিত করুন।

সংযোগ কৌশল

একটি বাস্তবায়ন কৌশল হল প্রতিটি ডিভাইসকে সার্ভার হিসাবে স্বয়ংক্রিয়ভাবে প্রস্তুত করা যাতে প্রতিটি ডিভাইসে একটি সার্ভার সকেট খোলা থাকে এবং সংযোগের জন্য শোনা যায়। এই ক্ষেত্রে, উভয় ডিভাইস অন্যটির সাথে একটি সংযোগ শুরু করতে পারে এবং ক্লায়েন্ট হতে পারে। বিকল্পভাবে, একটি ডিভাইস স্পষ্টভাবে সংযোগটি হোস্ট করতে পারে এবং চাহিদা অনুযায়ী একটি সার্ভার সকেট খুলতে পারে এবং অন্য ডিভাইসটি সংযোগ শুরু করে।


চিত্র 1. ব্লুটুথ পেয়ারিং ডায়ালগ।

একটি সার্ভার হিসাবে সংযোগ করুন

আপনি যখন দুটি ডিভাইস সংযোগ করতে চান, একটিকে অবশ্যই একটি খোলা BluetoothServerSocket ধরে সার্ভার হিসাবে কাজ করতে হবে। সার্ভার সকেটের উদ্দেশ্য হল ইনকামিং সংযোগের অনুরোধগুলি শোনা এবং অনুরোধ গৃহীত হওয়ার পরে একটি সংযুক্ত BluetoothSocket প্রদান করা। যখন BluetoothServerSocket থেকে BluetoothSocket অর্জিত হয়, তখন BluetoothServerSocket বাতিল করা যেতে পারে-এবং করা উচিত, যদি না আপনি ডিভাইসটি আরও সংযোগ গ্রহণ করতে চান।

একটি সার্ভার সকেট সেট আপ করতে এবং একটি সংযোগ গ্রহণ করতে, নিম্নলিখিত ধাপগুলির ক্রমটি সম্পূর্ণ করুন:

  1. listenUsingRfcommWithServiceRecord(String, UUID) কল করে একটি BluetoothServerSocket পান।

    স্ট্রিংটি আপনার পরিষেবার একটি শনাক্তযোগ্য নাম, যা সিস্টেম স্বয়ংক্রিয়ভাবে ডিভাইসে একটি নতুন সার্ভিস ডিসকভারি প্রোটোকল (SDP) ডাটাবেস এন্ট্রিতে লিখে দেয়। নামটি নির্বিচারে এবং কেবল আপনার অ্যাপের নাম হতে পারে। ইউনিভার্সলি ইউনিক আইডেন্টিফায়ার (UUID) এছাড়াও SDP এন্ট্রিতে অন্তর্ভুক্ত এবং ক্লায়েন্ট ডিভাইসের সাথে সংযোগ চুক্তির ভিত্তি তৈরি করে। অর্থাৎ, যখন ক্লায়েন্ট এই ডিভাইসের সাথে সংযোগ করার চেষ্টা করে, তখন এটি একটি UUID বহন করে যা অনন্যভাবে সেই পরিষেবাটিকে সনাক্ত করে যার সাথে এটি সংযোগ করতে চায়। সংযোগ গ্রহণ করার জন্য এই UUID গুলি অবশ্যই মিলবে৷

    একটি UUID হল একটি স্ট্রিং আইডির জন্য একটি প্রমিত 128-বিট ফর্ম্যাট যা অনন্যভাবে তথ্য সনাক্ত করতে ব্যবহৃত হয়। একটি UUID এমন তথ্য সনাক্ত করতে ব্যবহৃত হয় যা একটি সিস্টেম বা নেটওয়ার্কের মধ্যে অনন্য হওয়া প্রয়োজন কারণ একটি UUID পুনরাবৃত্তি হওয়ার সম্ভাবনা কার্যকরভাবে শূন্য। এটি একটি কেন্দ্রীভূত কর্তৃপক্ষের ব্যবহার ছাড়াই স্বাধীনভাবে তৈরি করা হয়। এই ক্ষেত্রে, এটি আপনার অ্যাপের ব্লুটুথ পরিষেবাকে অনন্যভাবে সনাক্ত করতে ব্যবহৃত হয়। আপনার অ্যাপের সাথে ব্যবহার করার জন্য একটি UUID পেতে, আপনি ওয়েবে অনেক র্যান্ডম UUID জেনারেটরের একটি ব্যবহার করতে পারেন, তারপর fromString(String) দিয়ে একটি UUID আরম্ভ করুন।

  2. accept() কল করে সংযোগের অনুরোধ শোনা শুরু করুন।

    এটি একটি ব্লকিং কল। এটি ফেরত আসে যখন হয় একটি সংযোগ গ্রহণ করা হয় বা একটি ব্যতিক্রম ঘটে। একটি সংযোগ শুধুমাত্র তখনই গৃহীত হয় যখন একটি দূরবর্তী ডিভাইস একটি UUID সমন্বিত একটি সংযোগ অনুরোধ পাঠায় যা এই লিসেনিং সার্ভার সকেটের সাথে নিবন্ধিত একটির সাথে মেলে। সফল হলে, accept() একটি সংযুক্ত BluetoothSocket ফেরত দেয়।

  3. আপনি অতিরিক্ত সংযোগ গ্রহণ করতে না চাইলে, close() কল করুন।

    এই পদ্ধতি কল সার্ভার সকেট এবং এর সমস্ত সংস্থান প্রকাশ করে, কিন্তু সংযুক্ত BluetoothSocket বন্ধ করে না যা accept() দ্বারা ফেরত দেওয়া হয়েছে। TCP/IP এর বিপরীতে, RFCOMM প্রতি চ্যানেলে একবারে শুধুমাত্র একটি সংযুক্ত ক্লায়েন্টকে অনুমতি দেয়, তাই বেশিরভাগ ক্ষেত্রেই একটি সংযুক্ত সকেট গ্রহণ করার সাথে সাথে BluetoothServerSocketclose() কল করা বোধগম্য হয়।

যেহেতু accept() কলটি একটি ব্লকিং কল, এটিকে মূল কার্যকলাপ UI থ্রেডে কার্যকর করবেন না। এটিকে অন্য থ্রেডে কার্যকর করা নিশ্চিত করে যে আপনার অ্যাপটি এখনও অন্যান্য ব্যবহারকারীর ইন্টারঅ্যাকশনে সাড়া দিতে পারে। আপনার অ্যাপ দ্বারা পরিচালিত একটি নতুন থ্রেডে একটি BluetoothServerSocket বা BluetoothSocket জড়িত এমন সমস্ত কাজ করা সাধারণত বোধগম্য হয়৷ একটি ব্লক করা কল বাতিল করতে যেমন accept() , BluetoothServerSocket বা অন্য থ্রেড থেকে BluetoothSocket -এ close() কল করুন। মনে রাখবেন যে BluetoothServerSocket বা BluetoothSocket সমস্ত পদ্ধতি থ্রেড-নিরাপদ।

উদাহরণ

নিম্নলিখিত সার্ভার উপাদানের জন্য একটি সরলীকৃত থ্রেড যা ইনকামিং সংযোগ গ্রহণ করে:

কোটলিন

private inner class AcceptThread : Thread() {

   private val mmServerSocket: BluetoothServerSocket? by lazy(LazyThreadSafetyMode.NONE) {
       bluetoothAdapter?.listenUsingInsecureRfcommWithServiceRecord(NAME, MY_UUID)
   }

   override fun run() {
       // Keep listening until exception occurs or a socket is returned.
       var shouldLoop = true
       while (shouldLoop) {
           val socket: BluetoothSocket? = try {
               mmServerSocket?.accept()
           } catch (e: IOException) {
               Log.e(TAG, "Socket's accept() method failed", e)
               shouldLoop = false
               null
           }
           socket?.also {
               manageMyConnectedSocket(it)
               mmServerSocket?.close()
               shouldLoop = false
           }
       }
   }

   // Closes the connect socket and causes the thread to finish.
   fun cancel() {
       try {
           mmServerSocket?.close()
       } catch (e: IOException) {
           Log.e(TAG, "Could not close the connect socket", e)
       }
   }
}

জাভা

private class AcceptThread extends Thread {
   private final BluetoothServerSocket mmServerSocket;

   public AcceptThread() {
       // Use a temporary object that is later assigned to mmServerSocket
       // because mmServerSocket is final.
       BluetoothServerSocket tmp = null;
       try {
           // MY_UUID is the app's UUID string, also used by the client code.
           tmp = bluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
       } catch (IOException e) {
           Log.e(TAG, "Socket's listen() method failed", e);
       }
       mmServerSocket = tmp;
   }

   public void run() {
       BluetoothSocket socket = null;
       // Keep listening until exception occurs or a socket is returned.
       while (true) {
           try {
               socket = mmServerSocket.accept();
           } catch (IOException e) {
               Log.e(TAG, "Socket's accept() method failed", e);
               break;
           }

           if (socket != null) {
               // A connection was accepted. Perform work associated with
               // the connection in a separate thread.
               manageMyConnectedSocket(socket);
               mmServerSocket.close();
               break;
           }
       }
   }

   // Closes the connect socket and causes the thread to finish.
   public void cancel() {
       try {
           mmServerSocket.close();
       } catch (IOException e) {
           Log.e(TAG, "Could not close the connect socket", e);
       }
   }
}

এই উদাহরণে, শুধুমাত্র একটি ইনকামিং সংযোগ কাঙ্ক্ষিত, তাই যত তাড়াতাড়ি একটি সংযোগ গ্রহণ করা হয় এবং BluetoothSocket অর্জিত হয়, অ্যাপটি অর্জিত BluetoothSocket একটি পৃথক থ্রেডে পাস করে, BluetoothServerSocket বন্ধ করে এবং লুপ থেকে বেরিয়ে যায়।

মনে রাখবেন যে যখন accept() BluetoothSocket ফেরত দেয়, তখন সকেটটি ইতিমধ্যেই সংযুক্ত থাকে। অতএব, আপনার connect() কল করা উচিত নয়, যেমন আপনি ক্লায়েন্টের দিক থেকে করেন।

অ্যাপ-নির্দিষ্ট manageMyConnectedSocket() পদ্ধতিটি ডেটা স্থানান্তর করার জন্য থ্রেড শুরু করার জন্য ডিজাইন করা হয়েছে, যা ব্লুটুথ ডেটা স্থানান্তর করার বিষয়ে আলোচনা করা হয়েছে।

সাধারণত, আপনি ইনকামিং সংযোগের জন্য শোনার সাথে সাথে আপনার BluetoothServerSocket বন্ধ করে দেওয়া উচিত। এই উদাহরণে, BluetoothSocket অর্জিত হওয়ার সাথে সাথে close() বলা হয়। আপনি আপনার থ্রেডে একটি সর্বজনীন পদ্ধতি প্রদান করতে চাইতে পারেন যা ব্যক্তিগত BluetoothSocket বন্ধ করে দিতে পারে যদি সেই সার্ভার সকেটে আপনাকে শোনা বন্ধ করতে হয়।

ক্লায়েন্ট হিসাবে সংযোগ করুন

একটি দূরবর্তী ডিভাইসের সাথে একটি সংযোগ শুরু করার জন্য যা একটি খোলা সার্ভার সকেটে সংযোগ গ্রহণ করছে, আপনাকে প্রথমে একটি BluetoothDevice অবজেক্ট পেতে হবে যা দূরবর্তী ডিভাইসের প্রতিনিধিত্ব করে। কিভাবে একটি BluetoothDevice তৈরি করতে হয় তা জানতে, ব্লুটুথ ডিভাইস খুঁজুন দেখুন। তারপরে আপনাকে অবশ্যই একটি BluetoothSocket অর্জন করতে এবং সংযোগ শুরু করতে BluetoothDevice ব্যবহার করতে হবে৷

মৌলিক পদ্ধতি নিম্নরূপ:

  1. BluetoothDevice ব্যবহার করে, createRfcommSocketToServiceRecord(UUID) কল করে একটি BluetoothSocket পান।

    এই পদ্ধতিটি একটি BluetoothSocket অবজেক্ট শুরু করে যা ক্লায়েন্টকে একটি BluetoothDevice এর সাথে সংযোগ করতে দেয়। এখানে পাস করা UUID অবশ্যই সার্ভার ডিভাইস দ্বারা ব্যবহৃত UUID এর সাথে মিলবে যখন এটি BluetoothServerSocket খুলতে listenUsingRfcommWithServiceRecord(String, UUID) বলে। একটি মিলে যাওয়া UUID ব্যবহার করতে, আপনার অ্যাপে UUID স্ট্রিংটিকে হার্ড-কোড করুন এবং তারপর সার্ভার এবং ক্লায়েন্ট কোড উভয় থেকে এটি উল্লেখ করুন।

  2. connect() কল করে সংযোগ শুরু করুন। মনে রাখবেন যে এই পদ্ধতিটি একটি ব্লকিং কল।

    একটি ক্লায়েন্ট এই পদ্ধতিতে কল করার পরে, সিস্টেমটি মিলিত UUID-এর সাথে দূরবর্তী ডিভাইসটি খুঁজে পেতে একটি SDP সন্ধান করে। যদি লুকআপ সফল হয় এবং দূরবর্তী ডিভাইস সংযোগটি গ্রহণ করে, এটি সংযোগের সময় ব্যবহার করার জন্য RFCOMM চ্যানেল শেয়ার করে এবং connect() পদ্ধতিটি ফিরে আসে। যদি সংযোগ ব্যর্থ হয়, বা connect() পদ্ধতিটি টাইম আউট হলে (প্রায় 12 সেকেন্ড পরে), তবে পদ্ধতিটি একটি IOException নিক্ষেপ করে।

যেহেতু connect() একটি ব্লকিং কল, আপনার সবসময় এই সংযোগ পদ্ধতিটি এমন একটি থ্রেডে করা উচিত যা প্রধান কার্যকলাপ (UI) থ্রেড থেকে আলাদা।

উদাহরণ

নিম্নলিখিতটি একটি ক্লায়েন্ট থ্রেডের একটি মৌলিক উদাহরণ যা একটি ব্লুটুথ সংযোগ শুরু করে:

কোটলিন

private inner class ConnectThread(device: BluetoothDevice) : Thread() {

   private val mmSocket: BluetoothSocket? by lazy(LazyThreadSafetyMode.NONE) {
       device.createRfcommSocketToServiceRecord(MY_UUID)
   }

   public override fun run() {
       // Cancel discovery because it otherwise slows down the connection.
       bluetoothAdapter?.cancelDiscovery()

       mmSocket?.let { socket ->
           // Connect to the remote device through the socket. This call blocks
           // until it succeeds or throws an exception.
           socket.connect()

           // The connection attempt succeeded. Perform work associated with
           // the connection in a separate thread.
           manageMyConnectedSocket(socket)
       }
   }

   // Closes the client socket and causes the thread to finish.
   fun cancel() {
       try {
           mmSocket?.close()
       } catch (e: IOException) {
           Log.e(TAG, "Could not close the client socket", e)
       }
   }
}

জাভা

private class ConnectThread extends Thread {
   private final BluetoothSocket mmSocket;
   private final BluetoothDevice mmDevice;

   public ConnectThread(BluetoothDevice device) {
       // Use a temporary object that is later assigned to mmSocket
       // because mmSocket is final.
       BluetoothSocket tmp = null;
       mmDevice = device;

       try {
           // Get a BluetoothSocket to connect with the given BluetoothDevice.
           // MY_UUID is the app's UUID string, also used in the server code.
           tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
       } catch (IOException e) {
           Log.e(TAG, "Socket's create() method failed", e);
       }
       mmSocket = tmp;
   }

   public void run() {
       // Cancel discovery because it otherwise slows down the connection.
       bluetoothAdapter.cancelDiscovery();

       try {
           // Connect to the remote device through the socket. This call blocks
           // until it succeeds or throws an exception.
           mmSocket.connect();
       } catch (IOException connectException) {
           // Unable to connect; close the socket and return.
           try {
               mmSocket.close();
           } catch (IOException closeException) {
               Log.e(TAG, "Could not close the client socket", closeException);
           }
           return;
       }

       // The connection attempt succeeded. Perform work associated with
       // the connection in a separate thread.
       manageMyConnectedSocket(mmSocket);
   }

   // Closes the client socket and causes the thread to finish.
   public void cancel() {
       try {
           mmSocket.close();
       } catch (IOException e) {
           Log.e(TAG, "Could not close the client socket", e);
       }
   }
}

লক্ষ্য করুন যে এই স্নিপেটে, সংযোগের প্রচেষ্টা হওয়ার আগে cancelDiscovery() কল করা হয়েছে। connect() এর আগে আপনার সর্বদা cancelDiscovery() কল করা উচিত, বিশেষ করে কারণ cancelDiscovery() সফল হয় তা নির্বিশেষে ডিভাইস আবিষ্কার বর্তমানে চলছে কিনা। আপনার অ্যাপ যদি ডিভাইস আবিষ্কারের কাজ চলছে কিনা তা নির্ধারণ করতে হয়, তাহলে আপনি isDiscovering() ব্যবহার করে পরীক্ষা করতে পারেন।

অ্যাপ-নির্দিষ্ট manageMyConnectedSocket() পদ্ধতিটি ডেটা স্থানান্তর করার জন্য থ্রেড শুরু করার জন্য ডিজাইন করা হয়েছে, যা ব্লুটুথ ডেটা স্থানান্তর করার বিষয়ে বিভাগে আলোচনা করা হয়েছে।

আপনার BluetoothSocket কাজ শেষ হলে, সর্বদা close() কল করুন। এটি করা অবিলম্বে সংযুক্ত সকেট বন্ধ করে এবং সমস্ত সম্পর্কিত অভ্যন্তরীণ সংস্থান প্রকাশ করে।