안드로이드(Andriod) 에서 다양한 네트워크 연결 및 데이터 받기 |
개발환경 : window 7 64bit, Eclipse Kepler, Android 4.2.2 |
안드로이드에서 소켓통신을 하기 위한 샘플 예제이다.
테스트를 하기 위해 java 서버프로세스를 준비하였다. 그 서버 프로세스를
띄운 상태에서 안드로이드 프로그램을 실행한다. 그리고 연결후에 서버로
부터 받은 데이터를 안드로이드 프로그램에서 표현한다.
1. 소켓연결을 위해 서버 프로그램 띄우기 |
테스트를 위해서 간단하게 서버역활을 할수 있는 프로그램을 하나 만든다.
이 프로그램은 서버소켓을 하나 만들고 대기 하고 있다가 Client 프로그램(안드로이드)
에서 요청이 들어 오면 OutputStream 를 이용해 데이터를 보낸다.
OutputStream 통해서 보낸 데이터는 안드로이드 Client 프로그램에서 받아 표현할 것이다.
프로그램은 스레드를 사용해서 만들지 않았기 때문에 한번 실행하고 대기 하고 있다가
요청에 응답하면 끝나는 형태의 아주 단순한 프로그램이다.
import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; import java.net.ServerSocket; import java.net.Socket; public class Main { public static void main(String[] args) { try{ ServerSocket serverSocket = new ServerSocket(0); System.out.println("I'm waiting here: " + serverSocket.getLocalPort()); Socket socket = serverSocket.accept(); System.out.println("from " + socket.getInetAddress() + ":" + socket.getPort()); OutputStream outputStream = socket.getOutputStream(); PrintStream printStream = new PrintStream(outputStream); printStream.print("Server Send data ~~ "); printStream.close(); socket.close(); }catch(IOException e){ System.out.println(e.toString()); } } }
2. 안드로이드 소켓통신을 하기 위한 준비 |
안드로이드에서 소켓통신을 하기위한 퍼미션 설정을 해야한다. 하지 않으면
아래와 같이 Permission denied 에러가 날수 있다.
java.net.SocketException: socket failed: EACCES (Permission denied)
AndroidManifest.xml 에 퍼미션 설정을 한다. Permissions 탭으로 들어가
User Permission 에 해당하는 android.permission.INTERNET 추가한다.
3. MainActivity 구성하기 |
메인화면은 간단하게 IP, PORT 입력란만 만들고 연결이벤트가 발생할수 있도록 하였다.
필요한 정보를 입력하고 버튼만 클릭하면 미리 띄워둔 서버 프로그램에 접속해
데이터를 받고 TextView 에 결과값을 출력하는 것이다.
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); edtTextAddress = (EditText) findViewById(R.id.address); edtTextPort = (EditText) findViewById(R.id.port); btnConnect = (Button) findViewById(R.id.connect); btnClear = (Button) findViewById(R.id.clear); txtResponse = (TextView) findViewById(R.id.response); btnConnect.setOnClickListener(buttonConnectOnClickListener); btnClear.setOnClickListener(new OnClickListener() { public void onClick(View v) { txtResponse.setText(""); } }); } // 클릭이벤트 리스너 OnClickListener buttonConnectOnClickListener = new OnClickListener() { public void onClick(View arg0) { NetworkTask myClientTask = new NetworkTask( edtTextAddress.getText().toString(), Integer.parseInt(edtTextPort.getText().toString()) ); myClientTask.execute(); } };
4. 네트워크 통신을 위한 AsyncTask 클래스 만들기 |
네트워크 통신을 위한 프로그램들은 비동기로 만들어져야 한다. 왜냐하면 프로그램
응답이 올때까지 기다릴수 없기 때문이다. 응답이 올때까지 먹통이 되면 안되기 때문이다.
Java 에서는 Thread 를 사용하겠지만 안드로이드에서는 AsyncTask 클래스를 제공해 준다.
이것을 상속받아 만드는데 시작할 때 수행하는 doInBackground() 함수와 onPostExecute()
만 구현하면된다.
그림에서 처럼 기본적으로 5개의 내부 Thread 가 생성되서 돌아가게 된다.
생성자에서 IP, PORT 정보를 넘긴다. 그리고 doInBackground() 에서는 Socket 객체를
생성한후 InputStream 을 통해 데이터를 받는다. onPostExecute() 에서는 받은 데이터를
표시하게 된다. 이곳에 표현하는 이유는 UI 스레드가 종료될 때 발생하는 함수 이기
때문이다. UI 가 다 표현 되지 않았는데 표현할려고 한다던지 UI스레드와 충돌을
방지 하기 위함이다.
public class NetworkTask extends AsyncTask{ String dstAddress; int dstPort; String response; NetworkTask(String addr, int port) { dstAddress = addr; dstPort = port; } @Override protected Void doInBackground(Void... arg0) { try { Socket socket = new Socket(dstAddress, dstPort); InputStream inputStream = socket.getInputStream(); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream( 1024); byte[] buffer = new byte[1024]; int bytesRead; while ((bytesRead = inputStream.read(buffer)) != -1) { byteArrayOutputStream.write(buffer, 0, bytesRead); } socket.close(); response = byteArrayOutputStream.toString("UTF-8"); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return null; } @Override protected void onPostExecute(Void result) { txtResponse.setText(response); super.onPostExecute(result); } }
5. 전체 소스와 실행화면 |
실행안드로이드 소스 : SampleConnector.zip
서버 소스 : ServerSocket.zip
package com.example.sampleconnector; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.Socket; import java.net.UnknownHostException; import android.app.Activity; import android.os.AsyncTask; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; public class MainActivity extends Activity { private TextView txtResponse; private EditText edtTextAddress, edtTextPort; private Button btnConnect, btnClear; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); edtTextAddress = (EditText) findViewById(R.id.address); edtTextPort = (EditText) findViewById(R.id.port); btnConnect = (Button) findViewById(R.id.connect); btnClear = (Button) findViewById(R.id.clear); txtResponse = (TextView) findViewById(R.id.response); btnConnect.setOnClickListener(buttonConnectOnClickListener); btnClear.setOnClickListener(new OnClickListener() { public void onClick(View v) { txtResponse.setText(""); } }); } // 클릭이벤트 리스너 OnClickListener buttonConnectOnClickListener = new OnClickListener() { public void onClick(View arg0) { NetworkTask myClientTask = new NetworkTask( edtTextAddress.getText().toString(), Integer.parseInt(edtTextPort.getText().toString()) ); myClientTask.execute(); } }; public class NetworkTask extends AsyncTask<Void, Void, Void> { String dstAddress; int dstPort; String response; NetworkTask(String addr, int port) { dstAddress = addr; dstPort = port; } @Override protected Void doInBackground(Void... arg0) { try { Socket socket = new Socket(dstAddress, dstPort); InputStream inputStream = socket.getInputStream(); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream( 1024); byte[] buffer = new byte[1024]; int bytesRead; while ((bytesRead = inputStream.read(buffer)) != -1) { byteArrayOutputStream.write(buffer, 0, bytesRead); } socket.close(); response = byteArrayOutputStream.toString("UTF-8"); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return null; } @Override protected void onPostExecute(Void result) { txtResponse.setText(response); super.onPostExecute(result); } } }
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:orientation="vertical" tools:context=".MainActivity" > <EditText android:id="@+id/address" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Address" /> <EditText android:id="@+id/port" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Port" /> <Button android:id="@+id/connect" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Connect..."/> <Button android:id="@+id/clear" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Clear"/> <TextView android:id="@+id/response" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </LinearLayout>
'안드로이드 개발' 카테고리의 다른 글
안드로이드(Android) Map 구현시 클릭이벤트로 화면좌표와 위도경도값 가져오기 (6) | 2014.02.18 |
---|---|
안드로이드(Android) 이클립스와 스마트폰 갤럭시 S 의 연결 (1) | 2014.02.17 |
안드로이드(Android) 이클립스와 갤럭시S3 의 연결을 위한 개발자 디버깅 설정 (7) | 2014.02.16 |
안드로이드(Android) DrawerLayout 사용하여 멀티윈도우 만들기 (3) | 2014.01.12 |
안드로이드(Android) activity 에서 activity 로 Object 넘기기 (1) | 2013.12.08 |
안드로이드(Android) 에서 ViewFlipper 을 이용해 화면 애니메이션 구현하기 (0) | 2013.11.24 |
안드로이드(Android) SeekBar 위젯을 이용해 화면 밝기 조정하기 (0) | 2013.10.28 |
안드로이드(android) WebView 페이지 이동과 웹에서 다운받은 파일 SDCARD 에서 확인 (0) | 2013.10.21 |