نمای کلی Wi-Fi Direct (همتا به همتا یا P2P)

Wi-Fi بی‌واسطه (P2P) به دستگاه‌های دارای سخت‌افزار مناسب اجازه می‌دهد مستقیماً ازطریق Wi-Fi و بدون نقطه دسترسی واسطه به یکدیگر متصل شوند. بااستفاده از این میاناهای برنامه‌سازی کاربردی، می‌توانید دستگاه‌های دیگر را پیدا کنید و به آن‌ها متصل شوید، به‌شرطی که هر دستگاه از Wi-Fi P2P پشتیبانی کند، سپس ازطریق اتصالی سریع در فاصله‌هایی بسیار طولانی‌تر از اتصال بلوتوث ارتباط برقرار کنید. این ویژگی برای برنامه‌هایی که داده‌ها را بین کاربران هم‌رسانی می‌کنند، مانند بازی‌های چندنفره یا برنامه‌های هم‌رسانی عکس، مفید است.

Wi-Fi P2P API از بخش‌های اصلی زیر تشکیل شده است:

  • روش‌هایی که به شما امکان می‌دهد همتایان را پیدا کنید، درخواست دهید، و به آن‌ها متصل شوید، که در کلاس WifiP2pManager تعریف شده‌اند.
  • شنوندگانی که به شما امکان می‌دهند از موفقیت یا شکست فراخوانی‌های روش WifiP2pManager مطلع شوید. هنگام فراخوانی روش‌های WifiP2pManager، هر روش می‌تواند شنونده خاصی را که به‌عنوان پارامتر ارسال شده است دریافت کند.
  • قصدها که شما را از رویدادهای خاصی که توسط چارچوب Wi-Fi P2P شناسایی شده‌اند، مانند قطع اتصال یا همتای جدید کشف‌شده، مطلع می‌کنند.

اغلب از این سه مؤلفه اصلی میاناهای برنامه‌سازی کاربردی باهم استفاده خواهید کرد. برای مثال، می‌توانید WifiP2pManager.ActionListener را برای تماس با discoverPeers() ارائه دهید تا روش‌های ActionListener.onSuccess() و ActionListener.onFailure() بتوانند به شما اطلاع دهند. اگر روش discoverPeers() متوجه شود که فهرست همتاها تغییر کرده است، هدف WIFI_P2P_PEERS_CHANGED_ACTION نیز پخش می‌شود.

نمای کلی میانای برنامه‌سازی کاربردی

کلاس WifiP2pManager روش‌هایی را ارائه می‌دهد که به شما امکان می‌دهد با سخت‌افزار Wi-Fi در دستگاهتان تعامل داشته باشید تا کارهایی مانند کاوش و اتصال به همتاها را انجام دهید. کنش‌های زیر دردسترس است:

جدول ۱. روش‌های Wi-Fi P2P

روش شرح
initialize() برنامه را در چارچوب Wi-Fi ثبت می‌کند. قبل‌از فراخوانی هر روش Wi-Fi P2P دیگری، این را فراخوانی کنید.
connect() اتصال همتابه‌همتا را با دستگاهی با پیکربندی مشخص‌شده شروع می‌کند.
cancelConnect() هرگونه مذاکره گروهی همتابه‌همتای درحال انجام را لغو می‌کند.
requestConnectInfo() اطلاعات اتصال دستگاه را درخواست می‌کند.
createGroup() گروه همتابه‌همتایی ایجاد می‌کند که دستگاه فعلی مالک گروه است.
removeGroup() گروه همتا به همتای فعلی را برمی‌دارد.
requestGroupInfo() اطلاعات گروه همتا به همتا را درخواست می‌کند.
discoverPeers() کاوش همتا را شروع می‌کند.
requestPeers() فهرست فعلی همتاهای شناسایی‌شده را درخواست می‌کند.

WifiP2pManager روش‌ها به شما اجازه می‌دهند یک شنونده را ارسال کنید تا چارچوب Wi-Fi P2P بتواند فعالیت شما را از وضعیت تماس مطلع کند. میاناهای شنونده دردسترس و فراخوانی‌های روش WifiP2pManager مربوطه که از شنونده‌ها استفاده می‌کنند در جدول ۲ شرح داده شده‌اند.

جدول ۲. شنوندگان همتابه‌همتای Wi-Fi

میانای شنونده کنش‌های مرتبط
WifiP2pManager.ActionListener ‫connect()،‏ cancelConnect()،‏ createGroup()،‏ removeGroup()، و discoverPeers()
WifiP2pManager.ChannelListener initialize()
WifiP2pManager.ConnectionInfoListener requestConnectInfo()
WifiP2pManager.GroupInfoListener requestGroupInfo()
WifiP2pManager.PeerListListener requestPeers()

Wi-Fi P2P APIs define intents that are broadcast when certain Wi-Fi P2P events happen, such as when a new peer is discovered or when a device's Wi-Fi state changes. می‌توانید برای دریافت این هدف‌ها در برنامه‌تان با ایجاد گیرنده رویداد ثبت‌شده که این هدف‌ها را مدیریت می‌کند ثبت‌نام کنید:

جدول ۳. Wi-Fi P2P Intents

قصد شرح
WIFI_P2P_CONNECTION_CHANGED_ACTION وقتی وضعیت اتصال Wi-Fi دستگاه تغییر می‌کند، پخش می‌شود.
WIFI_P2P_PEERS_CHANGED_ACTION وقتی با discoverPeers() تماس می‌گیرید، همه‌فرستی می‌شود. اگر این قصد را در برنامه‌تان مدیریت کنید، معمولاً برای دریافت فهرست به‌روزشده همتایان، requestPeers() را فراخوانی می‌کنید.
WIFI_P2P_STATE_CHANGED_ACTION وقتی Wi-Fi P2P در دستگاه فعال یا غیرفعال باشد، همه‌فرستی می‌کند.
WIFI_P2P_THIS_DEVICE_CHANGED_ACTION وقتی جزئیات دستگاهی تغییر کرده باشد، مثلاً نام دستگاه، همه‌فرستی می‌کند.

ایجاد گیرنده رویداد ثبت‌شده برای هدف‌های Wi-Fi P2P

گیرنده رویداد ثبت‌شده به شما امکان می‌دهد هدف‌های پخش‌شده توسط سیستم Android را دریافت کنید تا برنامه‌تان بتواند به رویدادهایی که به آن‌ها علاقه دارید پاسخ دهد. مراحل اصلی برای ایجاد گیرنده رویداد ثبت‌شده برای مدیریت Wi-Fi P2P هدف‌ها به شرح زیر است:

  1. کلاسی ایجاد کنید که کلاس BroadcastReceiver را گسترش دهد. برای سازنده کلاس، از پارامترهایی برای WifiP2pManager، WifiP2pManager.Channel، و فعالیتی که این گیرنده رویداد ثبت‌شده در آن ثبت خواهد شد استفاده خواهید کرد. این به گیرنده رویداد ثبت‌شده اجازه می‌دهد به‌روزرسانی‌ها را به فعالیت ارسال کند و همچنین درصورت نیاز به سخت‌افزار Wi-Fi و کانال ارتباطی دسترسی داشته باشد.

  2. در گیرنده رویداد ثبت‌شده، هدف‌های موردنظرتان را در روش onReceive() بررسی کنید. بسته به قصد دریافتی، کنش‌های لازم را انجام دهید. برای مثال، اگر گیرنده رویداد ثبت‌شده هدف WIFI_P2P_PEERS_CHANGED_ACTION را دریافت کند، می‌توانید روش requestPeers() را فراخوانی کنید تا فهرستی از همتایان فعلی کشف‌شده را دریافت کنید.

کد زیر نحوه ایجاد کردن گیرنده رویداد ثبت‌شده معمولی را نشان می‌دهد. گیرنده رویداد ثبت‌شده یک شیء WifiP2pManager و یک فعالیت را به‌عنوان آرگومان می‌گیرد و از این دو کلاس برای انجام مناسب اقدامات لازم هنگام دریافت هدف توسط گیرنده رویداد ثبت‌شده استفاده می‌کند:

کاتلین

/**
* A BroadcastReceiver that notifies of important Wi-Fi p2p events.
*/
class WiFiDirectBroadcastReceiver(
       private val manager: WifiP2pManager,
       private val channel: WifiP2pManager.Channel,
       private val activity: MyWifiActivity
) : BroadcastReceiver() {

   override fun onReceive(context: Context, intent: Intent) {
       val action: String = intent.action
       when (action) {
           WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION -> {
               // Check to see if Wi-Fi is enabled and notify appropriate activity
           }
           WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION -> {
               // Call WifiP2pManager.requestPeers() to get a list of current peers
           }
           WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION -> {
               // Respond to new connection or disconnections
           }
           WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION -> {
               // Respond to this device's wifi state changing
           }
       }
   }
}

جاوا

/**
* A BroadcastReceiver that notifies of important Wi-Fi p2p events.
*/
public class WiFiDirectBroadcastReceiver extends BroadcastReceiver {

   private WifiP2pManager manager;
   private Channel channel;
   private MyWiFiActivity activity;

   public WiFiDirectBroadcastReceiver(WifiP2pManager manager, Channel channel,
           MyWifiActivity activity) {
       super();
       this.manager = manager;
       this.channel = channel;
       this.activity = activity;
   }

   @Override
   public void onReceive(Context context, Intent intent) {
       String action = intent.getAction();

       if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
           // Check to see if Wi-Fi is enabled and notify appropriate activity
       } else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
           // Call WifiP2pManager.requestPeers() to get a list of current peers
       } else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
           // Respond to new connection or disconnections
       } else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {
           // Respond to this device's wifi state changing
       }
   }
}

در دستگاه‌های دارای Android نسخه ۱۰ و بالاتر، هدف‌های همه‌فرستی زیر غیرچسبنده هستند:

WIFI_P2P_CONNECTION_CHANGED_ACTION
برنامه‌ها می‌توانند از requestConnectionInfo()، requestNetworkInfo()، یا requestGroupInfo() برای بازیابی اطلاعات اتصال فعلی استفاده کنند.
WIFI_P2P_THIS_DEVICE_CHANGED_ACTION
برنامه‌ها می‌توانند از requestDeviceInfo() برای بازیابی اطلاعات اتصال فعلی استفاده کنند.

ایجاد کردن برنامه Wi-Fi P2P

ایجاد برنامه Wi-Fi P2P شامل ایجاد و ثبت گیرنده رویداد ثبت‌شده برای برنامه، یافتن همتاها، متصل شدن به همتا، و انتقال داده به همتا است. بخش‌های زیر نحوه انجام این کار را شرح می‌دهند.

راه‌اندازی اولیه

قبل‌از استفاده از Wi-Fi P2P API، باید مطمئن شوید که برنامه‌تان می‌تواند به سخت‌افزار دسترسی داشته باشد و دستگاه از پروتکل Wi-Fi P2P پشتیبانی می‌کند. اگر Wi-Fi P2P پشتیبانی می‌شود، می‌توانید نمونه‌ای از WifiP2pManager را دریافت کنید، گیرنده رویداد ثبت‌شده خود را ایجاد و ثبت کنید، و شروع به استفاده از Wi-Fi P2P APIs کنید.

  1. درخواست اجازه برای استفاده از سخت‌افزار Wi-Fi در دستگاه و اعلام برنامه شما برای داشتن نسخه حداقل صحیح کیت توسعه نرم‌افزار در مانیفست Android:

    <uses-sdk android:minSdkVersion="14" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <!-- If your app targets Android 13 (API level 33)
         or higher, you must declare the NEARBY_WIFI_DEVICES permission. -->
    <uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES"
                     <!-- If your app derives location information from
                          Wi-Fi APIs, don't include the "usesPermissionFlags"
                          attribute. -->
                     android:usesPermissionFlags="neverForLocation" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"
                     <!-- If any feature in your app relies on precise location
                          information, don't include the "maxSdkVersion"
                          attribute. -->
                     android:maxSdkVersion="32" />
    

    علاوه‌بر اجازه‌های قبلی، میاناهای برنامه‌سازی کاربردی زیر نیز به فعال بودن «حالت مکان» نیاز دارند:

  2. بررسی کنید که Wi-Fi P2P روشن باشد و از آن پشتیبانی شود. جای خوب برای بررسی این موضوع در گیرنده رویداد ثبت‌شده شما است وقتی که هدف WIFI_P2P_STATE_CHANGED_ACTION را دریافت می‌کند. فعالیتتان را از وضعیت Wi-Fi P2P مطلع کنید و براساس آن واکنش نشان دهید:

    کاتلین

    override fun onReceive(context: Context, intent: Intent) {
    ...
    val action: String = intent.action
    when (action) {
       WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION -> {
           val state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1)
           when (state) {
               WifiP2pManager.WIFI_P2P_STATE_ENABLED -> {
                   // Wifi P2P is enabled
               }
               else -> {
                   // Wi-Fi P2P is not enabled
               }
           }
       }
    }
    ...
    }

    جاوا

    @Override
    public void onReceive(Context context, Intent intent) {
    ...
    String action = intent.getAction();
    if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
       int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
       if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
           // Wifi P2P is enabled
       } else {
           // Wi-Fi P2P is not enabled
       }
    }
    ...
    }
  3. در روش onCreate() فعالیتتان، نمونه‌ای از WifiP2pManager را دریافت کنید و با فراخوانی initialize()، برنامه‌تان را در چارچوب Wi-Fi P2P ثبت کنید. این روش WifiP2pManager.Channel را برمی‌گرداند که برای متصل کردن برنامه شما به چارچوب Wi-Fi P2P استفاده می‌شود. همچنین باید نمونه‌ای از گیرنده رویداد ثبت‌شده خود را با اشیاء WifiP2pManager و WifiP2pManager.Channel همراه با ارجاع به فعالیت خود ایجاد کنید. این کار به گیرنده رویداد ثبت‌شده شما امکان می‌دهد رویدادهای جالب را به فعالیت شما اطلاع دهد و آن را براساس آن به‌روز کند. همچنین به شما امکان می‌دهد درصورت لزوم وضعیت Wi-Fi دستگاه را دستکاری کنید:

    کاتلین

    val manager: WifiP2pManager? by lazy(LazyThreadSafetyMode.NONE) {
       getSystemService(Context.WIFI_P2P_SERVICE) as WifiP2pManager?
    }
    
    var channel: WifiP2pManager.Channel? = null
    var receiver: BroadcastReceiver? = null
    
    override fun onCreate(savedInstanceState: Bundle?) {
       ...
    
       channel = manager?.initialize(this, mainLooper, null)
       channel?.also { channel ->
           receiver = WiFiDirectBroadcastReceiver(manager, channel, this)
       }
    }

    جاوا

    WifiP2pManager manager;
    Channel channel;
    BroadcastReceiver receiver;
    ...
    @Override
    protected void onCreate(Bundle savedInstanceState){
       ...
       manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
       channel = manager.initialize(this, getMainLooper(), null);
       receiver = new WiFiDirectBroadcastReceiver(manager, channel, this);
       ...
    }
  4. فیلتر قصدی ایجاد کنید و همان قصدهایی را که گیرنده رویداد ثبت‌شده شما بررسی می‌کند اضافه کنید:

    کاتلین

    val intentFilter = IntentFilter().apply {
       addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION)
       addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION)
       addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION)
       addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION)
    }

    جاوا

    IntentFilter intentFilter;
    ...
    @Override
    protected void onCreate(Bundle savedInstanceState){
       ...
       intentFilter = new IntentFilter();
       intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
       intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
       intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
       intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
       ...
    }
  5. گیرنده رویداد ثبت‌شده را در روش onResume() فعالیتتان ثبت کنید و آن را در روش onPause() فعالیتتان لغو ثبت‌نام کنید:

    کاتلین

    /* register the broadcast receiver with the intent values to be matched */
    override fun onResume() {
       super.onResume()
       receiver?.also { receiver ->
           registerReceiver(receiver, intentFilter)
       }
    }
    
    /* unregister the broadcast receiver */
    override fun onPause() {
       super.onPause()
       receiver?.also { receiver ->
           unregisterReceiver(receiver)
       }
    }

    جاوا

    /* register the broadcast receiver with the intent values to be matched */
    @Override
    protected void onResume() {
       super.onResume();
       registerReceiver(receiver, intentFilter);
    }
    /* unregister the broadcast receiver */
    @Override
    protected void onPause() {
       super.onPause();
       unregisterReceiver(receiver);
    }
  6. وقتی WifiP2pManager.Channel را دریافت کردید و گیرنده رویداد ثبت‌شده را راه‌اندازی کردید، برنامه‌تان می‌تواند فراخوانی‌های روش Wi-Fi P2P را انجام دهد و هدف‌های Wi-Fi P2P را دریافت کند.

  7. برنامه‌تان را بااستفاده از ویژگی‌های Wi-Fi P2P ازطریق فراخوانی روش‌ها در WifiP2pManager پیاده‌سازی کنید.

بخش‌های بعدی نحوه انجام کنش‌های رایج مانند کاوش و اتصال به همتاها را شرح می‌دهد.

کاوش همتایان

برای شناسایی همتاهای دردسترس که در محدوده هستند و برای اتصال دردسترس‌اند، discoverPeers() را فراخوانی کنید. فراخوانی این تابع ناهمگام است و موفقیت یا شکست با onSuccess() و onFailure() به برنامه‌تان اطلاع داده می‌شود اگر WifiP2pManager.ActionListener ایجاد کرده باشید. روش onSuccess() فقط به شما اطلاع می‌دهد که فرایند کشف موفقیت‌آمیز بوده است و هیچ اطلاعاتی درباره همتاهای واقعی که کشف کرده است (درصورت وجود) ارائه نمی‌دهد. نمونه کد زیر نحوه راه‌اندازی این مورد را نشان می‌دهد.

کاتلین

manager?.discoverPeers(channel, object : WifiP2pManager.ActionListener {

   override fun onSuccess() {
       ...
   }

   override fun onFailure(reasonCode: Int) {
       ...
   }
})

جاوا

manager.discoverPeers(channel, new WifiP2pManager.ActionListener() {
   @Override
   public void onSuccess() {
       ...
   }

   @Override
   public void onFailure(int reasonCode) {
       ...
   }
});

اگر فرایند کشف موفقیت‌آمیز باشد و همتاها را شناسایی کند، سیستم هدف WIFI_P2P_PEERS_CHANGED_ACTION را همه‌فرستی می‌کند که می‌توانید در گیرنده همه‌فرستی به آن گوش دهید تا فهرستی از همتاها را دریافت کنید. وقتی برنامه‌تان قصد WIFI_P2P_PEERS_CHANGED_ACTION را دریافت می‌کند، می‌توانید فهرستی از همتایان کشف‌شده را با requestPeers() درخواست کنید. کد زیر نحوه راه‌اندازی این مورد را نشان می‌دهد.

کاتلین

override fun onReceive(context: Context, intent: Intent) {
   val action: String = intent.action
   when (action) {
       ...
       WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION -> {
           manager?.requestPeers(channel) { peers: WifiP2pDeviceList? ->
               // Handle peers list
           }
       }
       ...
   }
}

جاوا

PeerListListener myPeerListListener;
...
if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {

   // request available peers from the wifi p2p manager. This is an
   // asynchronous call and the calling activity is notified with a
   // callback on PeerListListener.onPeersAvailable()
   if (manager != null) {
       manager.requestPeers(channel, myPeerListListener);
   }
}

روش requestPeers() نیز ناهمگام است و می‌تواند فعالیت شما را وقتی فهرست همتایان با onPeersAvailable() دردسترس است، که در میانای WifiP2pManager.PeerListListener تعریف شده است، اطلاع دهد. روش onPeersAvailable()‏ WifiP2pDeviceList را دراختیارتان قرار می‌دهد که می‌توانید آن را تکرار کنید تا همتایی را برای اتصال پیدا کنید.

اتصال به همتایان

وقتی فهرستی از همتاهای احتمالی را دریافت کردید و دستگاهی را برای اتصال انتخاب کردید، متد connect() را برای اتصال به دستگاه فراخوانی کنید. این فراخوانی روش به شیء WifiP2pConfig نیاز دارد که حاوی اطلاعاتی درباره دستگاهی است که باید به آن متصل شود. WifiP2pManager.ActionListener می‌تواند موفقیت یا عدم موفقیت اتصال را به شما اطلاع دهد. کد زیر نحوه ایجاد اتصال به دستگاه را نشان می‌دهد.

کاتلین

val device: WifiP2pDevice = ...
val config = WifiP2pConfig()
config.deviceAddress = device.deviceAddress
channel?.also { channel ->
   manager?.connect(channel, config, object : WifiP2pManager.ActionListener {

       override fun onSuccess() {
           //success logic
       }

       override fun onFailure(reason: Int) {
           //failure logic
       }
   }
)}

جاوا

//obtain a peer from the WifiP2pDeviceList
WifiP2pDevice device;
WifiP2pConfig config = new WifiP2pConfig();
config.deviceAddress = device.deviceAddress;
manager.connect(channel, config, new ActionListener() {

   @Override
   public void onSuccess() {
       //success logic
   }

   @Override
   public void onFailure(int reason) {
       //failure logic
   }
});

انتقال داده

پس‌از برقراری اتصال، می‌توانید داده‌ها را بین دستگاه‌ها با سوکت منتقل کنید. مراحل اصلی انتقال داده‌ها به‌شرح زیر است:

  1. ServerSocket ایجاد کنید. این سوکت منتظر اتصال از مشتری در درگاه مشخص‌شده می‌ماند و تا زمانی که این اتفاق نیفتد، مسدود می‌شود، بنابراین این کار را در رشته پس‌زمینه انجام دهید.
  2. مشتری Socket ایجاد کنید. کارخواه از نشانی IP و درگاه سوکت سرور برای اتصال به دستگاه سرور استفاده می‌کند.
  3. ارسال داده از کارخواه به سرور. وقتی سوکت کارخواه با موفقیت به سوکت سرور متصل شد، می‌توانید داده‌ها را از کارخواه به سرور با جریان‌های بایت ارسال کنید.
  4. سوکت سرور منتظر اتصال مشتری می‌ماند (با روش accept()). این تماس تا زمانی که کارخواه متصل شود مسدود می‌شود، بنابراین این تماس را در رشته دیگری برقرار کنید. وقتی اتصال برقرار می‌شود، دستگاه سرور می‌تواند داده‌ها را از کارخواه دریافت کند.

مثال زیر، که از نمونه نمایشی Wi-Fi P2P اصلاح شده است، نحوه ایجاد این ارتباط سوکت کارخواه-سرور و انتقال تصاویر JPEG از کارخواه به سرور با سرویس را نشان می‌دهد. برای نمونه کامل و کاربردی، نسخه نمایشی را کامپایل و اجرا کنید.

کاتلین

class FileServerAsyncTask(
       private val context: Context,
       private var statusText: TextView
) : AsyncTask<Void, Void, String?>() {

   override fun doInBackground(vararg params: Void): String? {
       /**
        * Create a server socket.
        */
       val serverSocket = ServerSocket(8888)
       return serverSocket.use {
           /**
            * Wait for client connections. This call blocks until a
            * connection is accepted from a client.
            */
           val client = serverSocket.accept()
           /**
            * If this code is reached, a client has connected and transferred data
            * Save the input stream from the client as a JPEG file
            */
           val f = File(Environment.getExternalStorageDirectory().absolutePath +
                   "/${context.packageName}/wifip2pshared-${System.currentTimeMillis()}.jpg")
           val dirs = File(f.parent)

           dirs.takeIf { it.doesNotExist() }?.apply {
               mkdirs()
           }
           f.createNewFile()
           val inputstream = client.getInputStream()
           copyFile(inputstream, FileOutputStream(f))
           serverSocket.close()
           f.absolutePath
       }
   }

   private fun File.doesNotExist(): Boolean = !exists()

   /**
    * Start activity that can handle the JPEG image
    */
   override fun onPostExecute(result: String?) {
       result?.run {
           statusText.text = "File copied - $result"
           val intent = Intent(android.content.Intent.ACTION_VIEW).apply {
               setDataAndType(Uri.parse("file://$result"), "image/*")
           }
           context.startActivity(intent)
       }
   }
}

جاوا

public static class FileServerAsyncTask extends AsyncTask {

   private Context context;
   private TextView statusText;

   public FileServerAsyncTask(Context context, View statusText) {
       this.context = context;
       this.statusText = (TextView) statusText;
   }

   @Override
   protected String doInBackground(Void... params) {
       try {

           /**
            * Create a server socket and wait for client connections. This
            * call blocks until a connection is accepted from a client
            */
           ServerSocket serverSocket = new ServerSocket(8888);
           Socket client = serverSocket.accept();

           /**
            * If this code is reached, a client has connected and transferred data
            * Save the input stream from the client as a JPEG file
            */
           final File f = new File(Environment.getExternalStorageDirectory() + "/"
                   + context.getPackageName() + "/wifip2pshared-" + System.currentTimeMillis()
                   + ".jpg");

           File dirs = new File(f.getParent());
           if (!dirs.exists())
               dirs.mkdirs();
           f.createNewFile();
           InputStream inputstream = client.getInputStream();
           copyFile(inputstream, new FileOutputStream(f));
           serverSocket.close();
           return f.getAbsolutePath();
       } catch (IOException e) {
           Log.e(WiFiDirectActivity.TAG, e.getMessage());
           return null;
       }
   }

   /**
    * Start activity that can handle the JPEG image
    */
   @Override
   protected void onPostExecute(String result) {
       if (result != null) {
           statusText.setText("File copied - " + result);
           Intent intent = new Intent();
           intent.setAction(android.content.Intent.ACTION_VIEW);
           intent.setDataAndType(Uri.parse("file://" + result), "image/*");
           context.startActivity(intent);
       }
   }
}

در کارخواه، با نقطه پایانی مشتری به سوکت سرور متصل شوید و داده‌ها را منتقل کنید. این نمونه یک فایل JPEG را در سیستم فایل دستگاه کارخواه منتقل می‌کند.

کاتلین

val context = applicationContext
val host: String
val port: Int
val len: Int
val socket = Socket()
val buf = ByteArray(1024)
...
try {
   /**
    * Create a client socket with the host,
    * port, and timeout information.
    */
   socket.bind(null)
   socket.connect((InetSocketAddress(host, port)), 500)

   /**
    * Create a byte stream from a JPEG file and pipe it to the output stream
    * of the socket. This data is retrieved by the server device.
    */
   val outputStream = socket.getOutputStream()
   val cr = context.contentResolver
   val inputStream: InputStream = cr.openInputStream(Uri.parse("path/to/picture.jpg"))
   while (inputStream.read(buf).also { len = it } != -1) {
       outputStream.write(buf, 0, len)
   }
   outputStream.close()
   inputStream.close()
} catch (e: FileNotFoundException) {
   //catch logic
} catch (e: IOException) {
   //catch logic
} finally {
   /**
    * Clean up any open sockets when done
    * transferring or if an exception occurred.
    */
   socket.takeIf { it.isConnected }?.apply {
       close()
   }
}

جاوا

Context context = this.getApplicationContext();
String host;
int port;
int len;
Socket socket = new Socket();
byte buf[]  = new byte[1024];
...
try {
   /**
    * Create a client socket with the host,
    * port, and timeout information.
    */
   socket.bind(null);
   socket.connect((new InetSocketAddress(host, port)), 500);

   /**
    * Create a byte stream from a JPEG file and pipe it to the output stream
    * of the socket. This data is retrieved by the server device.
    */
   OutputStream outputStream = socket.getOutputStream();
   ContentResolver cr = context.getContentResolver();
   InputStream inputStream = null;
   inputStream = cr.openInputStream(Uri.parse("path/to/picture.jpg"));
   while ((len = inputStream.read(buf)) != -1) {
       outputStream.write(buf, 0, len);
   }
   outputStream.close();
   inputStream.close();
} catch (FileNotFoundException e) {
   //catch logic
} catch (IOException e) {
   //catch logic
}

/**
* Clean up any open sockets when done
* transferring or if an exception occurred.
*/
finally {
   if (socket != null) {
       if (socket.isConnected()) {
           try {
               socket.close();
           } catch (IOException e) {
               //catch logic
           }
       }
   }
}