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의 이 세 가지 주요 구성요소를 함께 사용하는 경우가 많습니다. 예를 들어 ActionListener.onSuccess()ActionListener.onFailure() 메서드가 알림을 보낼 수 있도록 discoverPeers() 호출에 WifiP2pManager.ActionListener를 제공할 수 있습니다. 가 WIFI_P2P_PEERS_CHANGED_ACTION discoverPeers() 메서드가 동종 앱 목록이 변경되었습니다.

API 개요

WifiP2pManager 클래스는 기기의 Wi-Fi 하드웨어와 상호작용하여 검색, 피어 연결 등의 작업을 수행할 수 있게 하는 메서드를 제공합니다. 다음과 같은 작업이 가능합니다.

표 1. Wi-Fi P2P 메서드

방법 설명
initialize() Wi-Fi 프레임워크로 애플리케이션을 등록합니다. 다음 날짜 이전에 호출 다른 Wi-Fi P2P 메서드를 호출할 수 없습니다.
connect() 지정된 구성이 있는 기기와 P2P 연결을 시작합니다.
cancelConnect() 모든 진행 중인 P2P 그룹 협상을 취소합니다.
requestConnectInfo() 기기의 연결 정보를 요청합니다.
createGroup() 현재 기기를 그룹 소유주로 하는 P2P 그룹을 생성합니다.
removeGroup() 현재 P2P 그룹을 삭제합니다.
requestGroupInfo() P2P 그룹 정보를 요청합니다.
discoverPeers() 피어 검색을 시작합니다.
requestPeers() 검색된 피어의 최신 목록을 요청합니다.

WifiP2pManager 메서드는 리스너를 전달해 Wi-Fi P2P 프레임워크에서 호출 상태에 관한 Activity를 알림으로 받을 수 있도록 합니다. 사용 가능한 리스너 인터페이스와 해당하는 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 상태가 변경되었을 때가 이에 해당합니다. 이러한 인텐트를 처리하는 Broadcast Receiver를 생성하여 애플리케이션에서 이 인텐트를 수신하도록 등록할 수 있습니다.

표 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 인텐트의 Broadcast Receiver 만들기

Broadcast Receiver는 Android 시스템에서 브로드캐스트하는 인텐트를 수신하여 애플리케이션이 관심 대상인 이벤트에 응답할 수 있게 합니다. Wi-Fi P2P 인텐트를 처리하기 위한 Broadcast Receiver를 생성하는 기본적인 단계는 다음과 같습니다.

  1. BroadcastReceiver 클래스를 확장하는 클래스를 만듭니다. 수업용 WifiP2pManager의 매개변수를 사용합니다. WifiP2pManager.Channel 및 이 broadcast receiver가 실행할 활동 등록할 수 있습니다. 이렇게 하면 broadcast receiver가 와이파이 하드웨어와 통신망에 액세스할 수 있어야 합니다. 사용할 수 있습니다.

  2. Broadcast Receiver에서 onReceive() 메서드에서 관심이 있는 인텐트를 확인합니다. 수신한 인텐트에 따라 필요한 작업을 실행합니다. 예를 들어 broadcast receiver가 WIFI_P2P_PEERS_CHANGED_ACTION 인텐트가 포함된 경우 requestPeers()를 호출할 수 있습니다. 메서드를 사용하여 현재 검색된 피어의 목록을 가져옵니다.

다음 코드는 일반적인 Broadcast Receiver를 생성하는 방법을 보여줍니다. 이 broadcast receiver는 WifiP2pManager 객체와 활동을 인수로 사용 이 두 가지 클래스를 사용하여 broadcast receiver가 인텐트를 수신합니다.

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

자바

/**
* 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의 인스턴스를 가져와서 Broadcast receiver를 등록하고 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가 켜져 있고 지원되는지 확인합니다. 이를 확인하기에 좋은 곳은 broadcast receiver를 수신하면 WIFI_P2P_STATE_CHANGED_ACTION 인텐트를 처리하세요. Activity에 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
               }
           }
       }
    }
    ...
    }

    자바

    @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 프레임워크 또한 Activity에 대한 참조와 더불어 WifiP2pManagerWifiP2pManager.Channel 객체로 Broadcast Receiver의 인스턴스를 생성해야 합니다. 이렇게 하면 broadcast receiver를 통해 흥미있는 이벤트를 활동에 알리고 그에 따라 업데이트하세요. 또한 를 사용하면 필요한 경우 기기의 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)
       }
    }

    자바

    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. 인텐트 필터를 만들고 broadcast receiver와 동일한 인텐트 추가 다음을 확인합니다.

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

    자바

    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() 메서드에서 broadcast receiver를 등록하고 활동의 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)
       }
    }

    자바

    /* 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를 가져와 Broadcast Receiver를 설정하면 애플리케이션이 Wi-Fi P2P 메서드를 호출하고 Wi-Fi P2P 인텐트를 수신할 수 있습니다.

  7. 다음을 호출하여 Wi-Fi P2P 기능을 사용하여 애플리케이션을 구현합니다. WifiP2pManager에 있습니다.

다음 섹션에서는 Cloud Shell에서 검색 및 외부 IP 주소가 있는지 확인할 수 있습니다

피어 검색

discoverPeers()를 호출하여 범위 내에 있고 연결할 수 있는 사용 가능한 피어를 탐지합니다. 이 함수 호출은 비동기식이며, WifiP2pManager.ActionListener를 생성한 경우 onSuccess()onFailure()과 함께 애플리케이션에 성공 또는 실패가 전달됩니다. onSuccess() 메서드만 탐색 프로세스가 성공했음을 알리고 발견한 실제 피어에 대한 정보 다음 코드 샘플이 이를 설정하는 방법을 보여줍니다.

Kotlin

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

   override fun onSuccess() {
       ...
   }

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

자바

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

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

검색 프로세스가 성공하고 피어를 감지하면 시스템이 브로드캐스트에서 수신 대기할 수 있는 WIFI_P2P_PEERS_CHANGED_ACTION 인텐트 수신자를 지정하여 피어 목록을 가져옵니다. 애플리케이션이 WIFI_P2P_PEERS_CHANGED_ACTION 인텐트가 포함된 경우 발견된 대상 목록을 요청할 수 있습니다. requestPeers()와 피어링됩니다. 다음 코드는 이를 설정하는 방법을 보여줍니다.

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

자바

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

자바

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

자바

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