Visão geral do Wi-Fi Direct (ponto a ponto ou P2P)

Wi-Fi Direct (P2P) permite que dispositivos com o hardware adequado se conectem diretamente via Wi-Fi sem um ponto de acesso intermediário. Com essas APIs, é possível descobrir e se conectar a outros dispositivos quando cada um deles for compatível com Wi-Fi P2P, se comunicam por uma conexão veloz por distâncias muito maiores Conexão Bluetooth. Isso é útil para aplicativos que compartilham dados entre usuários, como um jogo multiplayer ou um app de compartilhamento de fotos.

As APIs de Wi-Fi P2P são constituídas das seguintes partes principais:

  • Métodos que permitem descobrir, solicitar e conectar-se a pares, que são definida no classe WifiP2pManager.
  • Os listeners que permitem que você seja notificado sobre a conclusão ou a falha das chamadas de método WifiP2pManager. Ao chamar métodos WifiP2pManager, cada um deles pode receber um listener específico transmitido como um parâmetro.
  • Intents que notificam você sobre eventos específicos detectados pela estrutura Wi-Fi P2P, como uma conexão interrompida ou um ponto recém-descoberto.

Muitas vezes, você usará esses três componentes principais das APIs juntos. Para por exemplo, é possível fornecer WifiP2pManager.ActionListener a uma chamada para discoverPeers() para que ActionListener.onSuccess() e ActionListener.onFailure() métodos podem notificar você. Um WIFI_P2P_PEERS_CHANGED_ACTION também será transmitida se o método discoverPeers() descobrir que o lista de apps semelhantes mudou.

Visão geral da API

A classe WifiP2pManager fornece métodos para permitir que você interaja com o hardware Wi-Fi do seu dispositivo e realize tarefas como encontrar e se conectar a pontos. As seguintes ações estão disponíveis:

Tabela 1. Métodos do Wi-Fi P2P

Método Descrição
initialize() Registra o aplicativo com a biblioteca Wi-Fi. Chame esse método antes de chamar qualquer outro método Wi-Fi P2P.
connect() Inicia uma conexão ponto a ponto com um dispositivo com a configuração especificada.
cancelConnect() Cancela qualquer negociação de grupo ponto a ponto em andamento.
requestConnectInfo() Solicita informações de conexão de um dispositivo.
createGroup() Cria um grupo ponto a ponto com o dispositivo atual como proprietário do grupo.
removeGroup() Remove o atual grupo ponto a ponto.
requestGroupInfo() Solicita informações do grupo ponto a ponto.
discoverPeers() Inicia a descoberta do ponto.
requestPeers() Solicita a lista atual de pontos descobertos.

Os métodos WifiP2pManager permitem transmitir um listener para que a estrutura Wi-Fi P2P possa notificar sua atividade sobre o status de uma chamada. As interfaces disponíveis do listener e a Chamadas de método WifiP2pManager que usam os listeners são descritos na tabela 2.

Tabela 2. Listeners Wi-Fi P2P

Interface do listener Ações associadas
WifiP2pManager.ActionListener connect(), cancelConnect(). createGroup(), removeGroup() e discoverPeers()
WifiP2pManager.ChannelListener initialize()
WifiP2pManager.ConnectionInfoListener requestConnectInfo()
WifiP2pManager.GroupInfoListener requestGroupInfo()
WifiP2pManager.PeerListListener requestPeers()

As APIs de Wi-Fi P2P definem intents transmitidos quando certos eventos de Wi-Fi P2P acontecem, como a descoberta de um novo ponto ou quando o estado do Wi-Fi de um dispositivo é alterado. Para se registrar para receber esses intents no seu aplicativo, Como criar um broadcast receiver que processa essas intents:

Tabela 3. Intents de Wi-Fi P2P

Intent Descrição
WIFI_P2P_CONNECTION_CHANGED_ACTION Transmitido quando o estado da conexão Wi-Fi do dispositivo muda.
WIFI_P2P_PEERS_CHANGED_ACTION Transmitir quando você ligar para discoverPeers(). Normalmente, você vai chamar requestPeers() para conferir uma lista atualizada de pontos, se processar essa intent no seu app.
WIFI_P2P_STATE_CHANGED_ACTION Transmitido quando o Wi-Fi P2P está ativado ou desativado no dispositivo.
WIFI_P2P_THIS_DEVICE_CHANGED_ACTION Transmitido quando os detalhes de um dispositivo foram alterados, como o nome dele.

Criar um broadcast receiver para intents de Wi-Fi P2P

Um broadcast receiver permite que você receba intents transmitidas pelo Android para que seu aplicativo possa responder a eventos nos quais você está interessado Siga estas etapas básicas para criar um broadcast receiver e gerenciar intents de Wi-Fi P2P:

  1. Crie uma classe que estenda a BroadcastReceiver. No construtor da classe, você vai usar parâmetros para o WifiP2pManager, WifiP2pManager.Channel e a atividade em que esse broadcast receiver será registrado. Isso permite que o broadcast receiver envie atualizações para o e acesso ao hardware Wi-Fi e a um sistema de comunicação se necessário.

  2. No broadcast receiver, verifique os intents em que você está interessado no método onReceive(). Executar as ações necessárias dependendo da intent recebidos. Por exemplo, se o broadcast receiver receber uma intent WIFI_P2P_PEERS_CHANGED_ACTION, você poderá chamar o método requestPeers() para conferir uma lista dos pontos descobertos recentemente.

O código a seguir mostra como criar um broadcast receiver típico. O broadcast receiver aciona um objeto WifiP2pManager e uma atividade como argumentos e usa essas duas classes para realizar adequadamente as ações necessárias quando o broadcast receiver recebe uma 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
       }
   }
}

Em dispositivos com o Android 10 e versões mais recentes, as seguintes intents de transmissão não são fixas:

WIFI_P2P_CONNECTION_CHANGED_ACTION
Os aplicativos podem usar requestConnectionInfo(), requestNetworkInfo(), ou requestGroupInfo() para recuperar as informações atuais de conexão.
WIFI_P2P_THIS_DEVICE_CHANGED_ACTION
Os aplicativos podem usar requestDeviceInfo() para extrair as informações de conexão atuais.

Criar um aplicativo Wi-Fi P2P

A criação de um aplicativo Wi-Fi P2P envolve criar e registrar uma transmissão. receptor para seu aplicativo, descobrindo pontos, conectando-se a um ponto e ou transferir dados para um peer. As seções a seguir descrevem como fazer isso.

Configuração inicial

Antes de usar as APIs de Wi-Fi P2P, é preciso verificar se o aplicativo pode acessar o hardware e se o dispositivo é compatível com o protocolo Wi-Fi P2P. Se Há suporte para Wi-Fi P2P. Você pode acessar uma instância de WifiP2pManager, criar registrar seu broadcast receiver e começar a usar as APIs do Wi-Fi P2P.

  1. Solicitar permissão para usar o hardware Wi-Fi no dispositivo e declarar que o aplicativo tenha a versão mínima correta do SDK no sistema manifest:

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

    Além das permissões anteriores, as seguintes APIs também exigem Location Modo a ser ativado:

  2. Verifique se o Wi-Fi P2P está ativado e é compatível. Um bom lugar para verificar isso é no seu broadcast receiver quando ele receber a intent WIFI_P2P_STATE_CHANGED_ACTION. Notificar sua atividade do Wi-Fi P2P e reagir de acordo:

    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
       }
    }
    ...
    }
    
  3. Na seção onCreate() consiga uma instância de WifiP2pManager e registre seu aplicativo com o framework Wi-Fi P2P chamando initialize(). Esse método retorna um WifiP2pManager.Channel, que é usado para conectar seu aplicativo ao framework do Wi-Fi P2P. Você também precisa criar uma instância do seu broadcast receiver com os objetos WifiP2pManager e WifiP2pManager.Channel, além de uma referência à atividade. Isso permite que o broadcast receiver notifique sua atividade de eventos interessantes e faça as atualizações correspondentes. Também é possível gerenciar o estado do Wi-Fi do dispositivo, se necessário:

    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);
       ...
    }
    
  4. Criar um filtro de intent e adicionar as mesmas intents que o broadcast receiver verifica se há:

    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);
       ...
    }
    
  5. Registre o broadcast receiver no método onResume() da sua e cancele a inscrição na método onPause() da sua atividade:

    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);
    }
    
  6. Quando você receber uma WifiP2pManager.Channel e configurar uma transmissão receptor, seu aplicativo pode fazer chamadas de método Wi-Fi P2P e receber Intents P2P.

  7. Implemente seu aplicativo usando os recursos do Wi-Fi P2P chamando os métodos em WifiP2pManager.

As próximas seções descrevem como realizar ações comuns, como descobrir e se conectar a pontos.

Descobrir pontos

Chame discoverPeers() para detectar pontos disponíveis que estão no intervalo e disponíveis para conexão. A chamada para essa função é assíncrona e um sucesso ou falha é comunicada ao aplicativo com onSuccess() e onFailure(). se você criou um WifiP2pManager.ActionListener. O método onSuccess() só notifica que o processo de descoberta foi bem-sucedido e não fornece nenhuma informação sobre os pontos encontrados. O seguinte exemplo de código mostra como fazer essa configuração.

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

Se o processo de descoberta for bem-sucedido e detectar pares, o sistema transmitirá o Intent WIFI_P2P_PEERS_CHANGED_ACTION, que pode ser detectada em uma transmissão receptor para receber uma lista de pares. Quando seu aplicativo recebe o WIFI_P2P_PEERS_CHANGED_ACTION, será possível solicitar uma lista das em peering com requestPeers(). O código a seguir mostra como configurar isso.

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

O método requestPeers() também é assíncrono e pode notificar sua atividade quando uma lista de pontos estiver disponível com onPeersAvailable(), que é definido na interface WifiP2pManager.PeerListListener. O método onPeersAvailable() fornece um WifiP2pDeviceList, que pode ser iterado para encontrar o ponto de conexão.

Conectar pontos

Depois de conseguir uma lista de possíveis colegas e selecionar um dispositivo para se conectar chame o método connect() para se conectar ao dispositivo. Essa chamada de método exige um objeto WifiP2pConfig que contenha informações sobre o dispositivo a ser conectado. WifiP2pManager.ActionListener pode notificar você sobre o sucesso de uma conexão ou falha. O código a seguir mostra como criar uma conexão com um dispositivo.

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

Transferir dados

Depois que uma conexão for estabelecida, você poderá transferir dados entre os dispositivos com soquetes. Veja as etapas básicas da transferência de dados:

  1. Crie um ServerSocket. Esse soquete aguarda uma conexão de um cliente em uma porta especificada e a bloqueia até que ela aconteça. Por isso, realize essa ação em um thread em segundo plano.
  2. Crie um cliente Socket. O cliente usa o endereço IP e a porta do soquete do servidor para se conectar ao dispositivo do servidor.
  3. Envie os dados do cliente para o servidor. Quando o soquete do cliente se conecta ao soquete do servidor, é possível enviar dados do cliente para o servidor com streams de bytes.
  4. O soquete do servidor aguarda uma conexão do cliente (com o método accept()). Esta chamada é bloqueado até que um cliente se conecte. Por isso, chame isso em outra linha de execução. Quando um Se uma conexão for estabelecida, o dispositivo servidor poderá receber os dados do cliente.

O exemplo a seguir, modificado do Wi-Fi P2P, Demonstração, mostra como criar a comunicação de soquete do cliente-servidor e transferir Imagens JPEG de um cliente para um servidor com um serviço. Para um exemplo completo de funcionamento, compile e execute a demonstração.

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

No cliente, conecte-se ao soquete do servidor com um soquete do cliente e transfira dados. Este exemplo transfere um arquivo JPEG no sistema de arquivos do dispositivo cliente.

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