본문 바로가기
Android/안드로이드 기본지식

wifi direct p2p 연결

by 붕어사랑 티스토리 2023. 1. 11.
반응형

https://developer.android.com/guide/topics/connectivity/wifip2p?hl=ko 

 

Wi-Fi Direct(P2P) 개요  |  Android 개발자  |  Android Developers

Wi-Fi Direct(P2P) 개요 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. Wi-Fi Direct(P2P)는 적절한 하드웨어를 갖춘 Android 4.0(API 레벨 14) 이상을 실행하는 기기가 중

developer.android.com

 

1. 개요

공식문서의 내용을 읽고 있는데 가독성이 도저히 안좋아서 좀더 편하게 읽기위해 블로글을 작성하게 되었다

 

WiFi-Direct란

와이파이 다이렉트란 P2P 연결을 해주는 기술이고 블루투스보다 훨씬 더 성능이 좋다. 특징은 다음과 같다.

 

  • 네트워크나 핫스팟에 연결되지 않아도 사용 가능하다
  • 보안문제가 섞여있고, 기기 근처의 범위에 연결하는게 목적이면 와이파이 다이렉트가 적합한 기술이다
  • WPA2 encryption을 지원한다. 대충 일반 네트워크 ad-hoc 뭐 이런거보다 좋다는 얘기인듯
  • 와이파이 다이렉트가 연결되는 두놈들 성능을 대충 비교해서 서버역할을 정해준다. 서버역할을 하는놈을 그룹오너라고 하며 따로 직접 지정해 줄 수도 있다.

 

WiFi Direct의 구성요소

  • WiFiP2pManager : 피어를 검색하고 연결할 수 있는 클래스로 가장 중요한 핵심 클래스다
  • 리스너 : 매니저 클래스의 각종 상태를 감시하는 리스너이다
  • 인텐트 : 와이파이 프레임워크에서 탐지된 특정 이벤트에 알림을 보내는 인텐트

리스너는 대충 콜백이고, 인텐트는 딱 보면 추후에 브로드캐스트리시버를 사용하여 특정 작업을 하는 것 을 알 수 있다

 

 

API 목록(WiFiP2pManager안에 있는)

아래 API들은 추후 사용될 api이므로 잘 숙지하자. 생각보다 얼마 없다

 

  • initialize() : wifi 프레임워크로 앱을 등록하는 함수. 이게 무슨소리냐 하면 이 함수를 호출해야지 "나 와이파이 다이렉트 사용해요~" 하고 알리는것과 같다. 이함수는 channel이라는 것을 리턴한다
  • connect() : p2p 연결을 시작한다. 앞서 말한것 처럼 각 피어들이 initialize가 먼저 호출되야지 사용가능하다
  • cancleConnect() : p2p 연결을 종료한다
  • requestConnectInfo() : 기기의 연결정보를 요청한다
  • createGroup() : 현재 기기를 group owner로 하는 p2p 그륩을 만든다. 그륩이란 p2p로 연결된 모임이라는 뜻이고, 오너는 서버역할을 담당하는 기기이다.
  • removeGroup() : 현재 그륩을 삭제한다
  • requestGroupInfo() : p2p 그룹정보를 요청한다
  • discoverPeer() : 피어 검색을 시작한다
  • requestPeers() : 피어의 최신목록을 요청한다

 

노랑놈들은 중요한놈들. 반드시 기억할건 initialize를 호출해야 나 와이파이 다이렉트 사용해요~ 라고 하는것인점을 기억하자

 

리스너 목록

앞서 말한 리스너의 목록들이다. 우측은 리스너와 관련된 API들의 모음이다. 대충 넘어가세요

리스너 인터페이스 관련된 작업
WifiP2pManager.ActionListener connect(), cancelConnect(), createGroup(), removeGroup() discoverPeers()
WifiP2pManager.ChannelListener initialize()
WifiP2pManager.ConnectionInfoListener requestConnectInfo()
WifiP2pManager.GroupInfoListener requestGroupInfo()
WifiP2pManager.PeerListListener requestPeers()

 

인텐트

아래 내용들은 사용되는 인텐트 필터 목록들이다. 대충 넘어가세요

 

인텐트 설명
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 기기의 상세 정보(: 기기 이름) 변경되었는지 브로드캐스트합니다.

 

 

 

브로드캐스트 리시버 만들기

본격적으로 와이파이 다이렉트를 만들어 봅시다. 먼저 관련된 브로드캐스트 리시버를 만들어야 됩니다. 아래와 같이 생성해줍니다.

하나는 코틀린, 하나는 자바코드이며, 생성자에 와이파이 매니저와, 그리고 이니셜라이징 하면 나오는 채널, 그리고 와이파이 다이렉트를 사용하는 액티비티를 넣어줍니다.

 

이 세가지를 생성자에 넣는것은 브로드캐스트 리시버에서 사용될 가능성이 크기 때문입니다.

 

브로드캐스트 리시버에 대한 지식이 없다면 먼저 브로드캐스트 리시버에 대한 내용을 공부하는것을 추천드립니다.

/**
 * 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 mManager;
    private Channel mChannel;
    private MyWiFiActivity mActivity;

    public WiFiDirectBroadcastReceiver(WifiP2pManager manager, Channel channel,
            MyWifiActivity activity) {
        super();
        this.mManager = manager;
        this.mChannel = channel;
        this.mActivity = 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
        }
    }
}

 

 

 

권한 설정

아래는 와이파이 다이렉트에 필요한 권한들입니다. 매니페스트에 설정해줍시다

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

 

위에서 제일 중요한것은 FINE_LOCATION인데 저렇게 해도 권한설정이 안될 때가 있습니다. 그때는 아래처럼 수동으로 퍼미션 리퀘스트를 날려줍시다.

if (ActivityCompat.checkSelfPermission(
                this,
                Manifest.permission.ACCESS_FINE_LOCATION
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            ActivityCompat.requestPermissions(this@MainActivity,
                arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), 1)
        }

 

 

 

WiFi 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
                활성화가 안될 시 여기에 코드를 작성합니다
            }
        }
    }
}
...
}
ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
@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
        활성화가 안될 시 여기에 코드를 작성합니다
    }
}
...
}

 

 

 

앱을 와이파이 프레임워크에 등록

앞서 말한것 처럼 이 작업은 "나 와이파이 다이렉트 사용해요~" 라고 하는 작업과 같다. initialize 메소드를 호출하면 이 작업을 해주며 기기가 피어로 검색이 가능해진다. initialize 메소드는 channel이라는 놈을 리턴하는데 이놈이 아주 중요한 기능이 많다.

 

그리고 인텐트 필터를 등록하여 브로드캐스트 리시버가 받아들일 필터들을 정의한다.

val manager: WifiP2pManager? by lazy(LazyThreadSafetyMode.NONE) {
    getSystemService(Context.WIFI_P2P_SERVICE) as WifiP2pManager?
}

var mChannel: WifiP2pManager.Channel? = null
var receiver: BroadcastReceiver? = null

override fun onCreate(savedInstanceState: Bundle?) {
    ...

    mChannel = manager?.initialize(this, mainLooper, null)
    mChannel?.also { channel ->
        receiver = WiFiDirectBroadcastReceiver(manager, channel, this)
    }
    
    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)
    }
	...
}
ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
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, mChannel, this);
    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);
    ...
}

 

 

브로드캐스트 리시버 등록

마지막으로 브로드캐스트 리시버를 액티비티 생명주기에 등록해주면 기본적인 뼈대는 완성이 된다!

/* register the broadcast receiver with the intent values to be matched */
override fun onResume() {
    super.onResume()
    mReceiver?.also { receiver ->
        registerReceiver(receiver, intentFilter)
    }
}

/* unregister the broadcast receiver */
override fun onPause() {
    super.onPause()
    mReceiver?.also { receiver ->
        unregisterReceiver(receiver)
    }
}
ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
/* register the broadcast receiver with the intent values to be matched */
@Override
protected void onResume() {
    super.onResume();
    registerReceiver(mReceiver, intentFilter);
}
/* unregister the broadcast receiver */
@Override
protected void onPause() {
    super.onPause();
    unregisterReceiver(mReceiver);
}

 

 

 

 

 

 

이로써 기본적인 구조는 완성되었다. 다음에 나올 내용들은 이제 위 구조에서 여러분들이 직접 활용하면 된다!

 

 

 

피어 검색하기

매니저의 discoverPeers() 함수를 이용하면 피어를 검색할 수 있다. ActionListListner라는 리스너를 달 수 있는데 피어검색의 성공여부만 알려주고 피어에 대한 정보는 알려주지 않는다.

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이라는 인텐트를 호출한다. 그럼 앞서배운 API인 requestPeers() 메소드(피어의 최신목록을 요청하는)를 호출해주자.

 

여기서 한가지 주목할점이 있다. 바로 리스너인데 코드를 보면 PeerListListener를 제공해주고 이 리스너 안에는 onPeersAvailable()이라는 메소드가 있다. 이 메소드를 통해 이용가능한 피어들을 WifiP2pDeviceList 형태로 제공받는다.

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

 

 

 

피어와의 연결

앞서 배운 내용으로 피어 디바이스 리스트를 전달받았다면 본격적으로 피어와 연결을 시도해보자. connect() 메소드를 이용하여 연결을 시도한다.

 

이때 WifiP2pConfig라는 객체를 전달해야된다. 이 객체에 전달받은 피어리스트의 deviceAddress를 넘겨주고 connect를 시도한다.

 

ActionListener를 이용하면 연결이 실패했는지 안했는지 알 수 있다

 

val device: WifiP2pDevice = ...
val config = WifiP2pConfig()
config.deviceAddress = device.deviceAddress
mChannel?.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
    }
});

 

 

데이터 주고받기

연결이 성공했다면 이제 데이터를 주고받을 수 있다. 데이터를 주고받는 방법은 소켓을 이용한다. 이용단계는 다음과 같다.

 

 

  • 서버측에서는 ServerSocket을 생성한다. 그 다음에 accept() 메소드를 호출하여 클라이언트와 연결될 때 까지 대기한다. 연결이 완료되면 메소드는 Socket을 리턴하고 이 인스턴스는 클라이언트를 가리킨다. 이 작업은 연결될 때 까지 블록킹 되므로 반드시 따로 스레드를 빼 주거나 백그라운드로 실행하자
  • 클라이언트측에서는 Socket을 생성하고 서버의 아이피주소와 포트번호를 이용하여 소켓을 연결한다.
  • 연결이 완료되면 데이터를 주고받을 수 있다

 

 

아래는 소켓을 이용하여 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()
    }
}
ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
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
            }
        }
    }
}

 

 

클라이언트 측 코드

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()
    }
}
ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
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
            }
        }
    }
}
반응형

댓글