Обзор Wi-Fi Direct (одноранговая или P2P)

Технология Wi-Fi Direct (P2P) позволяет устройствам с соответствующим оборудованием напрямую подключаться друг к другу по Wi-Fi без промежуточной точки доступа. Используя эти API, вы можете обнаруживать и подключаться к другим устройствам, если каждое устройство поддерживает Wi-Fi P2P, а затем обмениваться данными по высокоскоростному соединению на расстояниях, значительно превышающих расстояния по Bluetooth. Это полезно для приложений, которые обмениваются данными между пользователями, таких как многопользовательские игры или приложения для обмена фотографиями.

API для Wi-Fi P2P-сетей состоят из следующих основных частей:

  • Методы, позволяющие обнаруживать, запрашивать и подключаться к другим узлам, определены в классе WifiP2pManager .
  • Слушатели, позволяющие получать уведомления об успешном или неудачном выполнении вызовов методов WifiP2pManager . При вызове методов WifiP2pManager каждый метод может получать определенный слушатель, переданный в качестве параметра.
  • Интенты, которые уведомляют вас о конкретных событиях, обнаруженных платформой Wi-Fi P2P, таких как разрыв соединения или обнаружение нового пира.

Вы часто будете использовать эти три основных компонента API вместе. Например, вы можете передать WifiP2pManager.ActionListener в вызов discoverPeers() , чтобы методы ActionListener.onSuccess() и ActionListener.onFailure() могли вас уведомить. Интент WIFI_P2P_PEERS_CHANGED_ACTION также транслируется, если метод discoverPeers() обнаружит, что список пиров изменился.

Обзор API

Класс WifiP2pManager предоставляет методы, позволяющие взаимодействовать с Wi-Fi-оборудованием вашего устройства для таких задач, как обнаружение и подключение к другим устройствам. Доступны следующие действия:

Таблица 1. Методы Wi-Fi P2P

Метод Описание
initialize() Регистрирует приложение в среде Wi-Fi. Вызывайте этот метод перед вызовом любого другого метода P2P-соединения по Wi-Fi.
connect() Устанавливает одноранговое соединение с устройством, имеющим указанную конфигурацию.
cancelConnect() Отменяет любые текущие переговоры в рамках группового взаимодействия между участниками.
requestConnectInfo() Запрашивает информацию о подключении устройства.
createGroup() Создает одноранговую группу, владельцем которой является текущее устройство.
removeGroup() Удаляет текущую пиринговую группу.
requestGroupInfo() Запрашивает информацию о группах, объединяющих пользователей по принципу «равный равному».
discoverPeers() Инициирует поиск среди коллег.
requestPeers() Запрашивает текущий список обнаруженных узлов.

Методы WifiP2pManager позволяют передавать слушатель, чтобы платформа Wi-Fi P2P могла уведомлять вашу активность о состоянии вызова. Доступные интерфейсы слушателей и соответствующие вызовы методов WifiP2pManager , использующие слушатели, описаны в таблице 2.

Таблица 2. Слушатели Wi-Fi P2P

Интерфейс слушателя Связанные действия
WifiP2pManager.ActionListener connect() , cancelConnect() , createGroup() , removeGroup() и discoverPeers()
WifiP2pManager.ChannelListener initialize()
WifiP2pManager.ConnectionInfoListener requestConnectInfo()
WifiP2pManager.GroupInfoListener requestGroupInfo()
WifiP2pManager.PeerListListener requestPeers()

API Wi-Fi P2P определяют интенты, которые передаются широковещательно при возникновении определенных событий Wi-Fi P2P, например, при обнаружении нового участника сети или изменении состояния Wi-Fi устройства. Вы можете зарегистрироваться для получения этих интентов в своем приложении, создав широковещательный приемник , который обрабатывает эти интенты:

Таблица 3. Намерения P2P в Wi-Fi.

Намерение Описание
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 Сообщает об изменении данных устройства, например, его названия.

Создайте широковещательный приемник для P2P-интентов Wi-Fi.

Приёмник широковещательных сообщений позволяет принимать интенты, передаваемые системой Android, чтобы ваше приложение могло реагировать на интересующие вас события. Основные шаги по созданию приёмника широковещательных сообщений для обработки интентов Wi-Fi P2P следующие:

  1. Создайте класс, расширяющий класс BroadcastReceiver . В конструкторе класса используйте параметры для WifiP2pManager , WifiP2pManager.Channel и активности, в которой будет зарегистрирован этот широковещательный приемник. Это позволит широковещательному приемнику отправлять обновления в активность, а также иметь доступ к Wi-Fi-оборудованию и каналу связи при необходимости.

  2. В широковещательном приемнике проверьте наличие интересующих вас интентов в методе onReceive() . Выполните необходимые действия в зависимости от полученного интента. Например, если широковещательный приемник получает интент WIFI_P2P_PEERS_CHANGED_ACTION , вы можете вызвать метод requestPeers() , чтобы получить список обнаруженных в данный момент пиров.

Приведенный ниже код демонстрирует, как создать типичный широковещательный приемник. Широковещательный приемник принимает в качестве аргументов объект WifiP2pManager и Activity и использует эти два класса для соответствующего выполнения необходимых действий при получении намерения:

Котлин

/**
* 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
       }
   }
}

На устройствах под управлением Android 10 и выше следующие широковещательные интенты не являются "прилипающими":

WIFI_P2P_CONNECTION_CHANGED_ACTION
Приложения могут использовать requestConnectionInfo() , requestNetworkInfo() или requestGroupInfo() для получения информации о текущем соединении.
WIFI_P2P_THIS_DEVICE_CHANGED_ACTION
Приложения могут использовать requestDeviceInfo() для получения информации о текущем соединении.

Создайте приложение для P2P-сети Wi-Fi.

Создание приложения для Wi-Fi P2P включает в себя создание и регистрацию широковещательного приемника для вашего приложения, обнаружение пиров, подключение к пиру и передачу данных пиру. В следующих разделах описано, как это сделать.

Первоначальная настройка

Перед использованием API Wi-Fi P2P необходимо убедиться, что ваше приложение может получить доступ к оборудованию и что устройство поддерживает протокол Wi-Fi P2P. Если Wi-Fi P2P поддерживается, вы можете получить экземпляр WifiP2pManager , создать и зарегистрировать свой широковещательный приемник и начать использовать API Wi-Fi P2P.

  1. Запросите разрешение на использование Wi-Fi-оборудования устройства и укажите в манифесте Android, что ваше приложение имеет правильную минимальную версию SDK:

    <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" />
    

    Помимо указанных выше разрешений, для работы следующих API также требуется включение режима определения местоположения:

  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
               }
           }
       }
    }
    ...
    }

    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
       }
    }
    ...
    }
  3. В методе onCreate() вашего Activity получите экземпляр WifiP2pManager и зарегистрируйте ваше приложение в фреймворке Wi-Fi P2P, вызвав метод initialize() . Этот метод возвращает объект WifiP2pManager.Channel , который используется для подключения вашего приложения к фреймворку Wi-Fi P2P. Вам также следует создать экземпляр вашего широковещательного приемника с объектами WifiP2pManager и WifiP2pManager.Channel , а также ссылкой на ваше Activity. Это позволит вашему широковещательному приемнику уведомлять ваше Activity о важных событиях и соответствующим образом обновлять его. Это также позволит вам при необходимости управлять состоянием 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)
       }
    }

    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);
       ...
    }
  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)
    }

    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);
       ...
    }
  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)
       }
    }

    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);
    }
  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) {
       ...
   }
})

Java

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
           }
       }
       ...
   }
}

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);
   }
}

Метод 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
       }
   }
)}

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
   }
});

Передача данных

После установления соединения можно передавать данные между устройствами, имеющими разъемы. Основные этапы передачи данных следующие:

  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)
       }
   }
}

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);
       }
   }
}

На стороне клиента подключитесь к серверному сокету через клиентский сокет и передайте данные. В этом примере передается файл 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()
   }
}

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
           }
       }
   }
}