안드로이드 서버/클라이언트 소켓통신

-- Android 2012. 10. 5. 09:53
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.
안드로이드에서 소켓통신을 써야할 지 고민하다가 아래의 잘 정리된 글을 발견하여 정리해둔다.

 

<목표> [안드로이드] 서버/클라이언트 소켓(Socket) 통신하기

     

   

  오늘은  서버, 클라이언트의 소켓(Soket) 통신에 대해서 알아보겠습니다. 기존의 많은 안드로이드 어플리케이션이 각각의 서버를 이용하여 정보를 주고 받습니다. 아무래도 기기 내에서 만으로 서비스하기에는 한계가 있기 때문이죠. 정보를 저장하고, 서버에서 처리하여 결과를 주고, 클라이언트는 그 결과를 받아서 어플리케이션에 알맞은 동작을 취하도록 합니다. 트위터 서비스나 스마트폰을 이용해서 공짜 문자(통신료 제외)를 주고 받을 수 있는 것도 서비스를 제공하는 곳에서 서버를 두기 때문입니다. 그 덕분에 핸드폰을 벗어나 더 많은 정보를 처리할 수 있도록 할 수 있습니다.

 

  서버/클라이언트소켓통신은기존의자바를이용해서소켓통신을해보신분들이라면어렵지않게사용하실있습니다. 서버의소스자체는완전히자바소스로이루어지기때문이지요. 실제로서버는안드로이드를통해서돌리는것이아니라, 기존의자바프로그래밍을이용하여수행합니다. 클라이언트는당연히안드로이드로개발을해야겠지요. 오늘보여드릴예제소스는인터넷에돌아다니는간단한서버– 클라이언트 소켓 통신을 가지고 와서 나름대로 수정을 해본 것입니다. 기존의 샘플 코드가 하나의 메시지를 서버로 보내고 난 뒤에, 바로 클라이언트에서 기다리면서 데이터가 오기를 기다리는 형태로 제공되었습니다. 그렇기 때문에 클라이언트가 계속 데이터를 기다리면서 블록킹 되어 있는 상태에서만 프로그래밍이 돌아갔습니다. 이러한 부분을 수정하여 쓰레드를 이용하여 백그라운드에서 돌아가게 하여, 기존의 클라이언트에서는 원래의 프로그램이 수행되고, 서버에서 오는 정보를 받는 부분은 쓰레드를 통해 해결했습니다.

 

   먼저서버를만들자바코드를알아보고, 뒤에는안드로이드에서소켓통신을위한설정과정을간단한예제를통해서알아보겠습니다.

     

     

     

STEP 1  Java Source Code

     

  자바 코드는 두 가지를 다루게 됩니다. 처음은 서버를 돌리는 데 필요한 자버 코드를 알아보고, 두 번째는 안드로이드 클라이언트 코드를 알아보겠습니다.

 

 

  [[ 서버 ]]   TCP Server Java Code

 

import java.io.BufferedReader;

import java.io.BufferedWriter;

import java.io.InputStreamReader;

import java.io.OutputStreamWriter;

import java.io.PrintWriter;

import java.net.ServerSocket;

import java.net.Socket;

 

publicclass TCPServer implements Runnable {

    publicstaticfinalintServerPort = 9999;

    publicstaticfinal String ServerIP = "xxx.xxx.xxx.xxxx";

 

    @Override

    publicvoid run() {

        // TODO Auto-generated method stub

        try {

            System.out.println("S: Connecting...");

            ServerSocket serverSocket = new ServerSocket(ServerPort);

 

            while (true) {

                Socket client = serverSocket.accept();

                System.out.println("S: Receiving...");

 

                try {

                    BufferedReader in = new BufferedReader(

                    new InputStreamReader(client.getInputStream()));

                    String str = in.readLine();

                    System.out.println("S: Received: '" + str + "'");

                    PrintWriter out = new PrintWriter(new BufferedWriter(

                    new OutputStreamWriter(client.getOutputStream())),true);

                    out.println("Server Received " + str);

                } catch (Exception e) {

                    System.out.println("S: Error");

                    e.printStackTrace();

                } finally {

                    client.close();

                    System.out.println("S: Done.");

                }

            }

        } catch (Exception e) {

            System.out.println("S: Error");

            e.printStackTrace();

        }

    }

 

    publicstaticvoid main(String[] args) {

        // TODO Auto-generated method stub

        Thread desktopServerThread = new Thread(new TCPServer());

        desktopServerThread.start();

    }

}

 

   서버의 기능은 클라이언트에서 오는 데이터를 받아들이는 게 핵심입니다. 자신의 포트를 세팅하여 소켓을 여는 것부터 시작하여, 클라이언트에서 오는 정보를 받기 위해서 accept() 를 통해서 기다립니다. 그리고 데이터가 왔다는 신호가 오면 리더를 통해서 스트림을 읽어냅니다. 그리고 자신이 받은 스트림 정보를 다시 돌려보내는 역할을 합니다. 현재는 하나의 클라이언트와 컨넥트를 통해 데이터를 주고 받는 형식입니다. 많은 클라이언트와 통신하고 싶으면 클라이언트에 대한 정보를 저장하고, 여러 클라이언트에게 적절하게 보내는 기능을 추가하시면 되겠습니다.

 

 

   [[ 클라이언트 ]]   TCP Client Java Code

 

 

package socket.client;

 

import java.io.BufferedInputStream;

import java.io.BufferedReader;

import java.io.BufferedWriter;

import java.io.IOException;

import java.io.InputStream;

import java.io.InputStreamReader;

import java.io.OutputStreamWriter;

import java.io.PrintWriter;

import java.net.Socket;

import java.net.URL;

import java.net.URLConnection;

 

import org.apache.http.util.ByteArrayBuffer;

import android.app.Activity;

import android.os.Bundle;

import android.os.Handler;

import android.util.Log;

import android.view.View;

import android.view.View.OnClickListener;

import android.widget.Button;

import android.widget.EditText;

import android.widget.TextView;

import android.widget.Toast;

 

publicclass NewClient extends Activity {

    private String html = "";

    private Handler mHandler;

 

    private Socket socket;

    private String name;

    private BufferedReader networkReader;

    private BufferedWriter networkWriter;

    private String ip = "xxx.xxx.xxx.xxx"; // IP

    privateintport = 9999; // PORT번호

 

    @Override

    protectedvoid onStop() {

        // TODO Auto-generated method stub

        super.onStop();

        try {

            socket.close();

        } catch (IOException e) {

            // TODO Auto-generated catch block

            e.printStackTrace();

        }

    }

 

    publicvoid onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

        mHandler = new Handler();

 

        try {

            setSocket(ip, port);

        } catch (IOException e1) {

            // TODO Auto-generated catch block

            e1.printStackTrace();

        }

 

        checkUpdate.start();

 

        final EditText et = (EditText) findViewById(R.id.EditText01);

        Button btn = (Button) findViewById(R.id.Button01);

        final TextView tv = (TextView) findViewById(R.id.TextView01);

 

        btn.setOnClickListener(new OnClickListener() {

            publicvoid onClick(View v) {

                if (et.getText().toString() != null

                        || !et.getText().toString().equals("")) {

 

                    PrintWriter out = new PrintWriter(networkWriter, true);

                    String return_msg = et.getText().toString();

                    out.println(return_msg);

                }

            }

        });

    }

 

    private Thread checkUpdate = new Thread() {

        publicvoid run() {

            try {

                String line;

                Log.w("ChattingStart", "Start Thread");

                while (true) {

 

                    Log.w("Chatting is running", "chatting is running");

                    line = networkReader.readLine();

                    html = line;

                    mHandler.post(showUpdate);

                }

 

            } catch (Exception e) {

            }

        }

    };

 

    private Runnable showUpdate = new Runnable() {

        publicvoid run() {

            Toast.makeText(NewClient.this, "Coming word: " + html,

                    Toast.LENGTH_SHORT).show();

        }

    };

 

    publicvoid setSocket(String ip, int port) throws IOException {

        try {

            socket = new Socket(ip, port);

            networkWriter =

new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));

            networkReader =

new BufferedReader(new InputStreamReader(socket.getInputStream()));

            

        } catch (IOException e) {

            System.out.println(e);

            e.printStackTrace();

        }

    }

}

 

 

  이 번에 살펴볼 코드는 안드로이드 클라이언트 프로그램입니다. 안드로이드 클라이언트 코드에서는 서버에 소켓을 연결하고 받은 정보를 이용하여 프로그램을 수행시키는 것을 다룹니다. 먼저 onCreate()가 되면 서버에 연결하도록 설계되어 있습니다. IP 주소와 포트 번호를 알맞게 설정해주시고, 소켓을 연결합니다. 그리고 데이터를 주고 받기 위해서 리드, 라이터를 설정하여 둡니다. 예제에서는 간단히 텍스트 박스에 문자를 적고 버튼을 누르면, 서버로 데이터를 보냅니다. 그리고 서버에서 오는 데이터를 계속 받기 위해서 while을 쓰레드를 통해서 실행합니다. 여기서 받은 데이터 정보를 토스트 기능을 통해 출력합니다. 여기서 UI에 대한 접근을 핸들러를 통해서 하고 있는 것을 확인할 수 있습니다. 이렇게 하는 이유는 다른 포스트에 올리겠습니다. 일단 UI에 대한 접근은 핸들러를 통해서 수행한다고 생각하시고 프로그램을 수행해야한다는 것만 기억하시고 계시면 될 것 같습니다.

       

 

STEP 2  Xml Code

       

   Xml 코드에는 간단히 EditText에서 넣은 문자열을 버튼을 통해 서버로 데이터를 보내는 기본적인 기능만 추가하시면 됩니다.

 

<?xmlversion="1.0"encoding="utf-8"?>

<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"

  android:orientation="vertical"

  android:layout_width="fill_parent"

  android:layout_height="fill_parent">

  <TextViewandroid:id="@+id/TextView01"

  android:layout_height="wrap_content"

  android:layout_width="fill_parent"/>

  <EditTextandroid:id="@+id/EditText01"

  android:layout_height="wrap_content"

  android:layout_width="fill_parent"/>

  <Buttonandroid:id="@+id/Button01"

  android:layout_width="wrap_content"

  android:layout_height="wrap_content"

  android:text="Send"/>

  <TextViewandroid:id="@+id/chatting"

  android:layout_height="wrap_content"

  android:layout_width="fill_parent"/>  

</LinearLayout>

 

        

     

STEP 3  AndroidManifest.xml Code

     

   메니페스트에는 소켓을 이용하기위해 인터넷을 사용해야 하므로, 인터넷을 사용하겠다는 퍼미션만 추가해주시면 됩니다.

       

AndroidManifest.xml 에 추가해야할 인터넷 사용 허가권

<uses-permissionandroid:name="android.permission.INTERNET"/>

 

<?xmlversion="1.0"encoding="utf-8"?>

<manifestxmlns:android="http://schemas.android.com/apk/res/android"

package="socket.client"

 android:versionCode="1"

 android:versionName="1.0">

  <applicationandroid:icon="@drawable/icon"android:label="@string/app_name">

   <activityandroid:name=".NewClient"

    android:label="@string/app_name">

  <intent-filter>

   <actionandroid:name="android.intent.action.MAIN"/>

   <categoryandroid:name="android.intent.category.LAUNCHER"/>

  </intent-filter>

 </activity>

 </application>

  <uses-permissionandroid:name="android.permission.INTERNET"/>

</manifest>

     

     

     

 < 마무리 >  서버/클라이언트 소켓(Socket) 통신하기

     

 

  서버와클라이언트의소켓통신에대해서알아보았습니다. 핸드폰내에서의기능과정보만으로는어플리케이션이한정적일밖에없습니다. 그렇기때문에통신을통해서폭넓은서비스를제공하기위해서서버와클라이언트가서로통신할있도록소켓에대해서알아볼필요가있었습니다. 하나의서버가여러곳의클라이언트들에대해서서비스를해줘야때는클라이언트에대한정보를가지고있으면서소켓을각각연결시켜주어야합니다. 안드로이드클라이언트부분에서도현재수행되고있는동작에영향을받지않으면서백그라운드에서쓰레드가돌면서서버에서오는정보를수시로받을있도록해야합니다. 소켓통신에대한기존개념을알고계신분들이라면크게어렵지않게이해하실있으셨으리라봅니다. 처음접하시는분들은데이터를주고받는부분에서자신이수행하고싶은기능만추가해주시면간단히소켓통신을하실있으리라생각합니다.

출처 : http://pulsebeat.tistory.com/24

'-- Android' 카테고리의 다른 글

Back버튼을 두 번 눌러 종료  (0) 2012.10.05
Handling some android sqlite issues  (0) 2012.10.05
안드로이드 개발환경 구축  (0) 2012.09.20
Starting Another Activity  (0) 2012.09.18
Building a Simple User Interface  (0) 2012.09.14
posted by 어린왕자악꿍