Wi-Fi Direct(ピアツーピア(P2P))の概要

Wi-Fi Direct (P2P)を使用すると、適切なハードウェアを備えたデバイスを アクセス ポイントなしで Wi-Fi 経由で相互に通信できます。これらの API を使用すると、 他のデバイスを検出して接続できる(各デバイスが Wi-Fi P2P に対応している場合) スピーディーな通信で、インターネットよりはるかに長い距離を Bluetooth 接続。これは、複数のプロジェクト間でデータを共有する マルチプレーヤー ゲームや写真共有アプリケーションなど、ユーザーの操作を妨げることはありません。

Wi-Fi P2P API は、主に次の部分で構成されています。

  • ピアの検出、リクエスト、接続を可能にするメソッド。 で定義され、 WifiP2pManager クラス。
  • イベントの成功または失敗をユーザーが通知できるリスナー。 WifiP2pManager メソッド呼び出し。WifiP2pManager メソッドを呼び出すとき、 メソッドは、パラメータとして渡された特定のリスナーを受け取ることができます。
  • Wi-Fi P2P によって検出された特定のイベントを通知するインテント 接続の切断や新たに検出されたピアなどを検出できます。

多くの場合、API のこれら 3 つの主要コンポーネントを組み合わせて使用します。対象 たとえば、 WifiP2pManager.ActionListener ビデオ通話に discoverPeers() します。 ActionListener.onSuccess() および ActionListener.onFailure() 通知を受け取ることができます。 WIFI_P2P_PEERS_CHANGED_ACTION インテントがブロードキャストされる場合も、discoverPeers() メソッドが 変更されました。

API の概要

WifiP2pManager クラスには、Google Cloud Storage コンポーネントを ピアの検出や接続などを行うための、デバイスの Wi-Fi ハードウェア。 次の操作が可能です。

表 1. Wi-Fi P2P メソッド

方法 説明
initialize() アプリケーションを Wi-Fi フレームワークに登録します。この日時より前に呼び出す 他の Wi-Fi P2P メソッドを呼び出すこともできます。
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()

Wi-Fi P2P API は、特定の Wi-Fi P2P のときにブロードキャストされるインテントを定義します。 イベント(新しいピアの検出やデバイスの Wi-Fi 接続の試行など)が 必要があります。アプリケーションでこれらのインテントを受け取るよう登録するには、 ブロードキャスト レシーバの作成 関数が用意されています。

表 3: Wi-Fi P2P インテント

インテント 説明
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. API を拡張するクラスを作成する BroadcastReceiver クラス。 クラスの目標WifiP2pManager のパラメータを使用します。 WifiP2pManager.Channel と、このブロードキャスト レシーバが実行するアクティビティは 登録する必要があります。これにより、ブロードキャスト レシーバは、 アクセスできるだけでなく、Wi-Fi ハードウェアと できます。

  2. ブロードキャスト レシーバで、目的のインテントを確認します。 の onReceive() メソッドを呼び出します。インテントに応じて、必要なアクションを実行します。 受信します。たとえば、ブロードキャスト レシーバが WIFI_P2P_PEERS_CHANGED_ACTION インテントを呼び出すことで、requestPeers() メソッドを使用して、現在検出されているピアのリストを取得します。

次のコードは、一般的なブロードキャスト レシーバの作成方法を示しています。「 ブロードキャスト レシーバは、WifiP2pManager オブジェクトとアクティビティを引数として受け取ります。 これらの 2 つのクラスを使用して、必要なときに必要なアクションを ブロードキャスト レシーバがインテントを受信します。

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

Android 10 以降を搭載したデバイスでは、次のブロードキャスト インテントがあります。 べたつかない:

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 API の使用を開始します。

  1. デバイスで Wi-Fi ハードウェアを使用する権限をリクエストして、宣言する 最小 SDK バージョンをアプリに必要な Android デバイスに 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" />
    

    上記の権限に加えて、次の API には位置情報も必要です 有効にするモード:

  2. Wi-Fi P2P がオンになっていてサポートされているかどうかを確認します。ここをチェックすると 受信時にブロードキャスト レシーバが受信すると、 WIFI_P2P_STATE_CHANGED_ACTION インテント。Wi-Fi P2P のアクティビティを通知する それに応じて対応します。

    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. アクティビティの onCreate() メソッド、WifiP2pManager のインスタンスを取得してアプリケーションを登録する initialize() を呼び出して、Wi-Fi P2P フレームワークと連携させます。このメソッドは WifiP2pManager.Channel: アプリケーションを Wi-Fi P2P フレームワーク。また、ブロードキャストのインスタンスも作成する必要があります。 WifiP2pManager オブジェクトと WifiP2pManager.Channel オブジェクトを含むレシーバと、 アクティビティへの参照が含まれます。これにより、ブロードキャスト レシーバは 重要なイベントをアクティビティに通知し、適宜更新できます。また、 を使用すると、必要に応じてデバイスの Wi-Fi の状態を操作できます。

    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. インテント フィルタを作成し、ブロードキャスト レシーバと同じインテントを追加する 以下を確認します。

    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. ブロードキャスト レシーバを登録する onResume() メソッド onPause() のメソッド アクティビティ:

    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. WifiP2pManager.Channel を取得してブロードキャストを設定したとき アプリは Wi-Fi P2P メソッド呼び出しを行い、Wi-Fi からの P2P インテント。

  7. WifiP2pManager のメソッド。

以降のセクションでは、Google Cloud でのデータの検出、 内部 IP アドレスを使用して通信できます

同業他社を探す

discoverPeers() を呼び出して、範囲内にあり利用可能な使用可能なピアを検出します 接続しますこの関数の呼び出しは非同期で、成功または エラーは、onSuccess()onFailure() によってアプリケーションに通知されます。 (WifiP2pManager.ActionListener を作成した場合)。onSuccess() メソッドのみ 調査プロセスが成功したことが通知されます。 検出された実際のピアに関する情報(存在する場合)次の コードサンプルは、この設定方法を示しています。

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

検出プロセスが成功してピアを検出すると、システムは ブロードキャストでリッスンできる WIFI_P2P_PEERS_CHANGED_ACTION インテント ピアのリストを取得します。アプリケーションが WIFI_P2P_PEERS_CHANGED_ACTION インテントを呼び出すことで、検出された IP アドレスのリストを requestPeers() とピアリングします。次のコードは、その設定方法を示しています。

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

requestPeers() メソッドも非同期であり、アクティビティに通知できます。 ピアのリストが利用可能な場合 onPeersAvailable(), これは WifiP2pManager.PeerListListener インターフェースで定義されたものです。「 onPeersAvailable() メソッドを使用すると、 WifiP2pDeviceList は、 接続先のピアを探します

ピアに接続する

接続可能なピアのリストを取得して、接続するデバイスを選択したら、 connect() メソッドを呼び出してデバイスに接続します。このメソッド呼び出し WifiP2pConfig が必要 接続先のデバイスに関する情報を含むオブジェクトです。 WifiP2pManager.ActionListener は、接続の成功または 失敗します。次のコードは、デバイスへの接続を作成する方法を示しています。

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

データを移行する

接続が確立されたら、 使用します。データを転送する基本的な手順は次のとおりです。

  1. ServerSocket を作成します。このソケット 指定されたポートでのクライアントからの接続を待ち、接続が確立されるまでブロックします。 バックグラウンド スレッドで実行します。
  2. クライアント Socket を作成します。クライアントは サーバー デバイスに接続するサーバー ソケットの IP アドレスとポート。
  3. クライアントからサーバーにデータを送信します。クライアント ソケットが正常に サーバー ソケットに接続したら、クライアントから バイトストリームを消費します
  4. サーバー ソケットはクライアント接続( accept() メソッドなど)。この通話 クライアントが接続するまでブロックするため、これを別のスレッドで呼び出します。特定の サーバー デバイスはクライアントからのデータを受信できます。

次の例は、Wi-Fi P2P デモ、 クライアント / サーバー ソケットの通信と転送を作成して、 サービスを使用してクライアントからサーバーに送信される JPEG 画像。完全なデータセットを デモをコンパイルして実行します

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

クライアントで、クライアント ソケットを使用してサーバー ソケットに接続し、転送します。 分析できますこの例では、クライアント デバイスのファイル システムで JPEG ファイルを転送します。

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