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의 이 세 가지 주요 구성요소를 함께 사용하는 경우가 많습니다. 대상 예를 들어 WifiP2pManager.ActionListener 통화를 discoverPeers() 이렇게 하면 ActionListener.onSuccess()ActionListener.onFailure() 메서드가 여러분에게 알릴 수 있습니다. 가 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가 Activity에 업데이트를 전송하고, 필요한 경우 Wi-Fi 하드웨어와 통신 채널에 액세스할 수 있습니다.

  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 하드웨어를 사용하기 위한 권한을 요청하고 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가 켜져 있고 지원되는지 확인합니다. Broadcast Receiver가 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
               }
           }
       }
    }
    ...
    }
    

    자바

    @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. broadcast receiver를 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)
       }
    }
    

    자바

    /* 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() 메서드는 검색 프로세스가 성공했는지 여부만 알리고 발견한 실제 피어가 있어도 그에 대한 정보는 제공하지 않습니다. 다음 코드 샘플은 이를 설정하는 방법을 보여줍니다.

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