Wi-Fi Direct (P2P) permet aux appareils dotés du matériel approprié de se connecter directement les uns aux autres via le Wi-Fi, sans point d'accès intermédiaire. Grâce à ces API, vous pouvez découvrir d'autres appareils et vous y connecter lorsque chacun d'eux est compatible avec le Wi-Fi P2P. Vous pouvez ensuite communiquer via une connexion rapide sur des distances beaucoup plus longues qu'une connexion Bluetooth. Cela est utile pour les applications qui partagent des données entre les utilisateurs, comme un jeu multijoueur ou une application de partage de photos.
Les API Wi-Fi P2P se composent des parties principales suivantes :
- Méthodes qui vous permettent de découvrir des pairs, de leur envoyer des demandes et de vous connecter à eux, définies dans la classe
WifiP2pManager
. - Écouteurs qui vous permettent d'être averti de la réussite ou de l'échec des appels de méthode
WifiP2pManager
. Lorsque vous appelez des méthodesWifiP2pManager
, chacune d'elles peut recevoir un écouteur spécifique transmis en tant que paramètre. - Intents qui vous informent d'événements spécifiques détectés par le framework Wi-Fi P2P, comme une connexion interrompue ou un pair nouvellement découvert.
Vous utiliserez souvent ces trois principaux composants des API ensemble. Par exemple, vous pouvez fournir un WifiP2pManager.ActionListener
à un appel à discoverPeers()
afin que les méthodes ActionListener.onSuccess()
et ActionListener.onFailure()
puissent vous envoyer des notifications. Une intention WIFI_P2P_PEERS_CHANGED_ACTION
est également diffusée si la méthode discoverPeers()
découvre que la liste des pairs a changé.
Présentation de l'API
La classe WifiP2pManager
fournit des méthodes qui vous permettent d'interagir avec le matériel Wi-Fi de votre appareil pour effectuer des actions telles que la découverte et la connexion à des pairs.
Les actions suivantes sont disponibles :
Tableau 1. Méthodes Wi-Fi P2P
Méthode | Description |
initialize()
|
Enregistre l'application auprès du framework Wi-Fi. Appelez cette méthode avant d'appeler toute autre méthode Wi-Fi P2P. |
connect()
|
Démarre une connexion peer-to-peer avec un appareil ayant la configuration spécifiée. |
cancelConnect()
|
Annule toute négociation de groupe peer-to-peer en cours. |
requestConnectInfo()
|
Demande les informations de connexion d'un appareil. |
createGroup()
|
Crée un groupe peer-to-peer avec l'appareil actuel comme propriétaire du groupe. |
removeGroup()
|
Supprime le groupe pair à pair actuel. |
requestGroupInfo()
|
Demande des informations sur le groupe peer-to-peer. |
discoverPeers()
|
Lance la découverte des pairs. |
requestPeers()
|
Demande la liste actuelle des pairs détectés. |
Les méthodes WifiP2pManager
vous permettent de transmettre un écouteur afin que le framework Wi-Fi P2P puisse informer votre activité de l'état d'un appel. Les interfaces d'écouteur disponibles et les appels de méthode WifiP2pManager
correspondants qui utilisent les écouteurs sont décrits dans le tableau 2.
Tableau 2. Écouteurs Wi-Fi P2P
Interface d'écouteur | Actions associées |
WifiP2pManager.ActionListener
|
connect() , cancelConnect() ,
createGroup() , removeGroup() et
discoverPeers()
|
WifiP2pManager.ChannelListener
|
initialize()
|
WifiP2pManager.ConnectionInfoListener
|
requestConnectInfo()
|
WifiP2pManager.GroupInfoListener
|
requestGroupInfo()
|
WifiP2pManager.PeerListListener
|
requestPeers()
|
Les API Wi-Fi P2P définissent des intents qui sont diffusés lorsque certains événements Wi-Fi P2P se produisent, par exemple lorsqu'un nouvel homologue est découvert ou lorsque l'état Wi-Fi d'un appareil change. Vous pouvez vous inscrire pour recevoir ces intents dans votre application en créant un broadcast receiver qui gère ces intents :
Tableau 3 : Intents Wi-Fi P2P
Intention | Description |
WIFI_P2P_CONNECTION_CHANGED_ACTION
|
Diffusion lorsque l'état de la connexion Wi-Fi de l'appareil change. |
WIFI_P2P_PEERS_CHANGED_ACTION
|
Diffuser un message lorsque vous appelez discoverPeers() . Vous appelez généralement requestPeers() pour obtenir une liste à jour des pairs si vous gérez cette intention dans votre application.
|
WIFI_P2P_STATE_CHANGED_ACTION
|
Diffusion lorsque le Wi-Fi P2P est activé ou désactivé sur l'appareil. |
WIFI_P2P_THIS_DEVICE_CHANGED_ACTION
|
Diffusion lorsqu'un détail d'un appareil a changé, comme son nom. |
Créer un broadcast receiver pour les intents Wi-Fi P2P
Un récepteur de diffusion vous permet de recevoir les intents diffusés par le système Android, afin que votre application puisse répondre aux événements qui vous intéressent. Voici les étapes de base pour créer un récepteur de diffusion afin de gérer les intents Wi-Fi P2P :
Créez une classe qui étend la classe
BroadcastReceiver
. Pour le constructeur de la classe, vous utiliserez des paramètres pourWifiP2pManager
,WifiP2pManager.Channel
et l'activité dans laquelle ce récepteur de diffusion sera enregistré. Cela permet au récepteur de diffusion d'envoyer des mises à jour à l'activité et d'accéder au matériel Wi-Fi et à un canal de communication si nécessaire.Dans le récepteur de diffusion, recherchez les intents qui vous intéressent dans la méthode
onReceive()
. Effectuez les actions nécessaires en fonction de l'intention reçue. Par exemple, si le broadcast receiver reçoit une intentionWIFI_P2P_PEERS_CHANGED_ACTION
, vous pouvez appeler la méthoderequestPeers()
pour obtenir la liste des pairs actuellement détectés.
Le code suivant montre comment créer un récepteur de diffusion typique. Le broadcast receiver prend un objet WifiP2pManager
et une activité comme arguments, et utilise ces deux classes pour effectuer les actions nécessaires de manière appropriée lorsque le broadcast receiver reçoit un intent :
Kotlin
/** * 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 } } } }
Java
/** * 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 } } }
Sur les appareils équipés d'Android 10 ou version ultérieure, les intents de diffusion suivants ne sont pas persistants :
WIFI_P2P_CONNECTION_CHANGED_ACTION
Les applications - peuvent utiliser
requestConnectionInfo()
,requestNetworkInfo()
ourequestGroupInfo()
pour récupérer les informations de connexion actuelles. WIFI_P2P_THIS_DEVICE_CHANGED_ACTION
Les applications - peuvent utiliser
requestDeviceInfo()
pour récupérer les informations de connexion actuelles.
Créer une application Wi-Fi P2P
La création d'une application Wi-Fi P2P implique la création et l'enregistrement d'un récepteur de diffusion pour votre application, la découverte des pairs, la connexion à un pair et le transfert de données à un pair. Les sections suivantes expliquent comment procéder.
Configuration initiale
Avant d'utiliser les API Wi-Fi P2P, vous devez vous assurer que votre application peut accéder au matériel et que l'appareil est compatible avec le protocole Wi-Fi P2P. Si le Wi-Fi P2P est compatible, vous pouvez obtenir une instance de WifiP2pManager
, créer et enregistrer votre récepteur de diffusion, puis commencer à utiliser les API Wi-Fi P2P.
Demandez l'autorisation d'utiliser le matériel Wi-Fi de l'appareil et déclarez que votre application dispose de la version minimale requise du SDK dans le fichier manifeste 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" />
En plus des autorisations précédentes, les API suivantes nécessitent également que le mode Localisation soit activé :
Vérifiez si le Wi-Fi P2P est activé et compatible. Un bon endroit pour vérifier cela est votre récepteur de diffusion lorsqu'il reçoit l'intent
WIFI_P2P_STATE_CHANGED_ACTION
. Informez votre activité de l'état du Wi-Fi P2P et réagissez en conséquence :Kotlin
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 } } } } ... }
Java
@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 } } ... }
Dans la méthode
onCreate()
de votre activité, obtenez une instance deWifiP2pManager
et enregistrez votre application auprès du framework Wi-Fi P2P en appelantinitialize()
. Cette méthode renvoie un élémentWifiP2pManager.Channel
, qui permet de connecter votre application au framework Wi-Fi P2P. Vous devez également créer une instance de votre récepteur de diffusion avec les objetsWifiP2pManager
etWifiP2pManager.Channel
, ainsi qu'une référence à votre activité. Cela permet à votre récepteur de diffusion d'informer votre activité des événements intéressants et de la mettre à jour en conséquence. Il vous permet également de manipuler l'état du Wi-Fi de l'appareil si nécessaire :Kotlin
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) } }
Java
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); ... }
Créez un filtre d'intent et ajoutez les mêmes intents que ceux vérifiés par votre récepteur de diffusion :
Kotlin
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) }
Java
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); ... }
Enregistrez le broadcast receiver dans la méthode
onResume()
de votre activité et annulez son enregistrement dans la méthodeonPause()
de votre activité :Kotlin
/* 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) } }
Java
/* 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); }
Une fois que vous avez obtenu un
WifiP2pManager.Channel
et configuré un récepteur de diffusion, votre application peut effectuer des appels de méthode Wi-Fi P2P et recevoir des intents Wi-Fi P2P.Implémentez votre application en utilisant les fonctionnalités Wi-Fi P2P en appelant les méthodes dans
WifiP2pManager
.
Les sections suivantes décrivent comment effectuer des actions courantes, comme découvrir des pairs et s'y connecter.
Découvrir des applications similaires
Appelez discoverPeers()
pour détecter les pairs disponibles à portée et pouvant être connectés. L'appel de cette fonction est asynchrone. La réussite ou l'échec de l'opération est communiqué à votre application avec onSuccess()
et onFailure()
si vous avez créé un WifiP2pManager.ActionListener
. La méthode onSuccess()
vous informe uniquement que le processus de découverte a réussi. Elle ne fournit aucune information sur les pairs qu'elle a découverts, le cas échéant. L'exemple de code suivant montre comment configurer cela.
Kotlin
manager?.discoverPeers(channel, object : WifiP2pManager.ActionListener { override fun onSuccess() { ... } override fun onFailure(reasonCode: Int) { ... } })
Java
manager.discoverPeers(channel, new WifiP2pManager.ActionListener() { @Override public void onSuccess() { ... } @Override public void onFailure(int reasonCode) { ... } });
Si le processus de découverte réussit et détecte des pairs, le système diffuse l'intention WIFI_P2P_PEERS_CHANGED_ACTION
, que vous pouvez écouter dans un récepteur de diffusion pour obtenir une liste de pairs. Lorsque votre application reçoit l'intent WIFI_P2P_PEERS_CHANGED_ACTION
, vous pouvez demander une liste des pairs détectés avec requestPeers()
. Le code suivant montre comment configurer cela.
Kotlin
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 } } ... } }
Java
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); } }
La méthode requestPeers()
est également asynchrone et peut notifier votre activité lorsqu'une liste de pairs est disponible avec onPeersAvailable()
, qui est définie dans l'interface WifiP2pManager.PeerListListener
. La méthode onPeersAvailable()
vous fournit un WifiP2pDeviceList
, que vous pouvez parcourir pour trouver le pair auquel vous connecter.
Se connecter à des pairs
Une fois que vous avez obtenu une liste de pairs potentiels et sélectionné un appareil auquel vous connecter, appelez la méthode connect()
pour vous connecter à l'appareil. Cet appel de méthode nécessite un objet WifiP2pConfig
contenant des informations sur l'appareil auquel se connecter.
WifiP2pManager.ActionListener
peut vous informer de la réussite ou de l'échec d'une connexion. Le code suivant montre comment créer une connexion à un appareil.
Kotlin
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 } } )}
Java
//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 } });
Transférer des données
Une fois la connexion établie, vous pouvez transférer des données entre les appareils à l'aide de sockets. Voici les étapes de base du transfert de données :
- Créez un
ServerSocket
. Ce socket attend une connexion d'un client sur un port spécifié et se bloque jusqu'à ce que cela se produise. Effectuez donc cette opération dans un thread d'arrière-plan. - Créez un client
Socket
. Le client utilise l'adresse IP et le port du socket du serveur pour se connecter à l'appareil serveur. - Envoyez des données du client au serveur. Lorsque le socket client se connecte correctement au socket serveur, vous pouvez envoyer des données du client au serveur avec des flux d'octets.
- Le socket du serveur attend une connexion client (avec la méthode
accept()
). Cet appel se bloque jusqu'à ce qu'un client se connecte. Vous devez donc l'appeler dans un autre thread. Lorsqu'une connexion est établie, l'appareil serveur peut recevoir les données du client.
L'exemple suivant, modifié à partir de la démonstration Wi-Fi P2P, vous montre comment créer cette communication de socket client-serveur et transférer des images JPEG d'un client vers un serveur avec un service. Pour obtenir un exemple fonctionnel complet, compilez et exécutez la démo.
Kotlin
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) } } }
Java
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); } } }
Sur le client, connectez-vous au socket du serveur avec un socket client et transférez les données. Cet exemple transfère un fichier JPEG sur le système de fichiers de l'appareil client.
Kotlin
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() } }
Java
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 } } } }