반응형

이 앱은 자바언어를 학습하실 때 해봤던 소켓통신을 안드로이드에 적용한 예제입니다. 

소켓통신으로 단말기 끼리 1:1 채팅을 하는 예제로 서로 간단한 메세지를 주고받는 정도만 가능합니다.

정식 채팅 앱은 나중에 따로 포스트 할 예정입니다.


 한 대는 서버로 동작하고 한 대는 클라이언트가 되는 앱입니다. 서로 역할을 바꿀 수도 있습니다.


우선 단말기 간 테스트를 할 수 있도록 Genymotion의 에뮬레이터를 2대 준비합니다. 



프로그램을 Run 시킬때 아래처럼 연결되어 있는 디바이스가 2개 보이셔야 합니다.(각 단말기의 IP번호도 확인가능합니다.)




아래 소개될 소스코드를 2번 Run 해서 각각의 에뮬레이터에 동일한 앱을 설치합니다.


서버 (ip주소 : 192.168.0.101)

 

























클라이언트(ip주소 : 192.168.0.102)

 

























동일한 앱을 설치한 2대의 에뮬레이터를 각 각 서버와 클라이언트로 접속합니다.

그러면 서버 액티비티 화면과 클라이언트 액티비티 화면으로 전환합니다.


  서버

















 클라이언트




 서버와 클라이언트가 준비되면 먼저 서버쪽 부터 START 버튼을 클릭해서 서버를 구축합니다. 에러가 발생하지 않으면 잘 만들어진 겁니다. 서버에 에러가 없었다면 클라이언트쪽의 CONNECT SERVER 버튼을 클릭해서 서버에 접속합니다. 아래의 EditText 의 IP주소를 변경해서 서버의 역할을 바꿀 수도 있습니다.


서버 구축                                                서버에 접속

       






 에러가 없다면 접속이 잘 된 것입니다. 이제 각 각의 EditText View에 원하는 메세지를 작성하고 SEND 버튼을 클릭하면 서로에게 메세지가 전달되는 것을 확인할 수 있습니다.


 



 


















            








































Main 화면 Layout 파일

 activity_main.xml

 <RelativeLayout 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"

    tools:context="${relativePackage}.${activityClass}" >


    <Button

        android:id="@+id/btn_server"

        android:layout_width="200dp"

        android:layout_height="50dp"

        android:layout_centerHorizontal="true"

        android:layout_marginTop="200dp"

        android:gravity="center"

        android:text="Server"

        android:textSize="25sp"

        android:onClick="mOnClick"/>

    

    <Button

        android:id="@+id/btn_client"

        android:layout_width="200dp"

        android:layout_height="50dp"

        android:layout_centerHorizontal="true"

        android:layout_alignParentBottom="true"

        android:layout_marginBottom="200dp"

        android:gravity="center"

        android:text="Client"

        android:textSize="25sp"

        android:onClick="mOnClick"/>


</RelativeLayout>



Main 화면 소스파일

 

 MainActivity.java

public class MainActivity extends Activity {


@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

}

//Button을 클릭했을 때 호출되는 callback 메소드

public void mOnClick(View v){

Intent i;

switch(v.getId()){

case R.id.btn_server: //서버 화면

i= new Intent(this, ServerActivity.class);

startActivity(i);

break;

case R.id.btn_client: //클라이언트 화면

i= new Intent(this, ClientActivity.class);

startActivity(i);

break;

}

}

}






Server 화면 Layout 파일

 activity_server.xml

 <RelativeLayout 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:gravity="start"

    tools:context="${relativePackage}.${activityClass}" >


    <Button android:id="@+id/btn_start_server"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_centerHorizontal="true"

        android:layout_marginTop="20dp"

        android:text="START"

        android:textStyle="bold"

        android:onClick="mOnClick"/>

    

    <TextView android:id="@+id/label_message_from_client" 

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:layout_below="@id/btn_start_server"

        android:gravity="center"

        android:text="The Message from the client"

        android:textSize="20sp"

        android:textStyle="bold"

        android:textColor="#000000"

        android:layout_marginTop="50dp"/>

    

    <TextView android:id="@+id/text_massage_from_client"

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:layout_below="@id/label_message_from_client"

        android:text="text"

        android:gravity="center"

        android:layout_marginTop="20dp"/>

    

    <TextView android:id="@+id/label_message_to_client" 

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:layout_below="@id/text_massage_from_client"

        android:gravity="center"

        android:text="The Message to the client"

        android:textSize="20sp"

        android:textStyle="bold"

        android:textColor="#000000"

        android:layout_marginTop="50dp"/>

    

    <EditText android:id="@+id/edit_message_to_client"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_centerHorizontal="true"

        android:layout_below="@id/label_message_to_client"

        android:layout_marginTop="20sp"

        android:gravity="center"

        android:hint="Enter the message"/>

    

    <Button android:id="@+id/btn_send_server"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_centerHorizontal="true"

        android:layout_below="@id/edit_message_to_client"

        android:layout_marginTop="50dp"

        android:text="SEND"

        android:onClick="mOnClick"/>


</RelativeLayout>



Server 화면 소스파일

 

 ServerActivity.java

public class ServerActivity extends Activity {

static final int PORT=10001;

ServerSocket serversocket;

Socket socket;

DataInputStream is;

DataOutputStream os;

TextView text_msg; //클라이언트로부터 받을 메세지를 표시하는 TextView

EditText edit_msg; //클라이언트로 전송할 메세지를 작성하는 EditText

String msg="";

boolean isConnected=true;


@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_server);

text_msg= (TextView)findViewById(R.id.text_massage_from_client);

edit_msg= (EditText)findViewById(R.id.edit_message_to_client);

}

//Button 클릭시 자동으로 호출되는 callback 메소드

public void mOnClick(View v){

switch(v.getId()){

case R.id.btn_start_server: //채팅 서버 구축 및 클라이언트로 부터 메세지 받기

//Android API14버전이상 부터 네트워크 작업은 무조건 별도의 Thread에서 실행 해야함.

new Thread(new Runnable() {

@Override

public void run() {

// TODO Auto-generated method stub

try {

//서버소켓 생성.

serversocket=new ServerSocket(PORT);

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

try {

      //서버에 접속하는 클라이언트 소켓 얻어오기(클라이언트가 접속하면 클라이언트 소켓 리턴)

socket= serversocket.accept(); //서버는 클라이언트가 접속할 때까지 여기서 대기...

//여기 까지 왔다는 것은 클라이언트가 접속했다는 것을 의미하므로

//클라이언트와 데이터를 주고 받기 위한 통로구축..

is= new DataInputStream(socket.getInputStream()); //클라이언트로 부터 메세지를 받기 위한 통로

os= new DataOutputStream(socket.getOutputStream()); //클라이언트로 메세지를 보내기 위한 통로

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

//클라이언트가 접속을 끊을 때까지 무한반복하면서 클라이언트의 메세지 수신

while(isConnected){

try {

​                                     //클라이언트로 부터 메세지가 전송되면 이를 UTF형식으로 읽어서 String 으로 리턴​

msg=is.readUTF(); 

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

//클라이언트로부터 읽어들인 메시지msg를 TextView에 출력..

//안드로이드는 오직 main Thread 만이 UI를 변경할 수 있기에

//네트워크 작업을 하는 이 Thread에서는 TextView의 글씨를 직접 변경할 수 없음.

//runOnUiThread()는 별도의 Thread가 main Thread에게 UI 작업을 요청하는 메소드임.

runOnUiThread(new Runnable() {

@Override

public void run() {

// TODO Auto-generated method stub

text_msg.setText(msg);

}

});

/////////////////////////////////////////////////////////////////////////////

}//while..

}//run method...

}).start(); //Thread 실행..

break;

case R.id.btn_send_server: // 클라이언트로 메세지 전송하기.

if(os==null) return; //클라이언트와 연결되어 있지 않다면 전송불가..

//네트워크 작업이므로 Thread 생성

new Thread(new Runnable() {

@Override

public void run() {

// TODO Auto-generated method stub

//클라이언트로 보낼 메세지 EditText로 부터 얻어오기

String msg= edit_msg.getText().toString();

try {

os.writeUTF(msg); //클라이언트로 메세지 보내기.UTF 방식으로(한글 전송가능...)

os.flush();   //다음 메세지 전송을 위해 연결통로의 버퍼를 지워주는 메소드..    

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}).start(); //Thread 실행..

break;

}

}

}

   



 

Client 화면 Layout 파일

 activity_client.xml

 <RelativeLayout 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"

    tools:context="${relativePackage}.${activityClass}" >


    <Button android:id="@+id/btn_connectserver"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_centerHorizontal="true"

        android:layout_marginTop="20dp"

        android:text="CONNECT SERVER"

        android:textStyle="bold"

        android:onClick="mOnClick"/>

    

    <TextView android:id="@+id/label_message_from_server" 

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:layout_below="@id/btn_connectserver"

        android:gravity="center"

        android:text="The Message from the server"

        android:textSize="20sp"

        android:textStyle="bold"

        android:textColor="#000000"

        android:layout_marginTop="50dp"/>

    

    <TextView android:id="@+id/text_massage_from_server"

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:layout_below="@id/label_message_from_server"

        android:text="text"

        android:gravity="center"

        android:layout_marginTop="20dp"/>

    

    <TextView android:id="@+id/label_message_to_server" 

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:layout_below="@id/text_massage_from_server"

        android:gravity="center"

        android:text="The Message to the server"

        android:textSize="20sp"

        android:textStyle="bold"

        android:textColor="#000000"

        android:layout_marginTop="50dp"/>

    

    <EditText android:id="@+id/edit_message_to_server"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_centerHorizontal="true"

        android:layout_below="@id/label_message_to_server"

        android:layout_marginTop="20sp"

        android:gravity="center"

        android:hint="Enter the message"/>

    

    <Button android:id="@+id/btn_send_client"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_centerHorizontal="true"

        android:layout_below="@id/edit_message_to_server"

        android:layout_marginTop="50dp"

        android:text="SEND"

        android:onClick="mOnClick"/>

    

    <EditText android:id="@+id/edit_addressofserver"

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:hint="Enter the address of server"

        android:layout_alignParentBottom="true"

        android:layout_marginBottom="20dp"

        android:gravity="center"/>


</RelativeLayout>



Client 화면 소스파일

 

 ClientActivity.java

public class ClientActivity extends Activity {

private static final int PORT = 10001; //서버에서 설정한 PORT 번호

String ip="192.168.56.101"; //서버 단말기의 IP주소..

//본 예제는 Genymotion 에뮬레이터 2대로 테스한 예제입니다.

//Genymotion을 실행하면 각 에뮬레이터의 IP를 확인할 수 있습니다.

Socket socket;     //클라이언트의 소켓

DataInputStream is;

DataOutputStream os;

TextView text_msg;  //서버로 부터 받은 메세지를 보여주는 TextView

EditText edit_msg;  //서버로 전송할 메세지를 작성하는 EditText

EditText edit_ip;   //서버의 IP를 작성할 수 있는 EditText

String msg="";

boolean isConnected=true;


@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_client);

text_msg=(TextView)findViewById(R.id.text_massage_from_server);

edit_msg=(EditText)findViewById(R.id.edit_message_to_server);

edit_ip=(EditText)findViewById(R.id.edit_addressofserver);

edit_ip.setText(ip);

}

//Button 클릭시 자동으로 호출되는 callback 메소드

public void mOnClick(View v){

switch(v.getId()){

case R.id.btn_connectserver://서버에 접속하고 서버로 부터 메세지 수신하기

//Android API14버전이상 부터 네트워크 작업은 무조건 별도의 Thread에서 실행 해야함.

new Thread(new Runnable() {

@Override

public void run() {

// TODO Auto-generated method stub

try {

ip= edit_ip.getText().toString();//IP 주소가 작성되어 있는 EditText에서 서버 IP 얻어오기

//서버와 연결하는 소켓 생성..

socket= new Socket(InetAddress.getByName(ip), PORT );

//여기까지 왔다는 것을 예외가 발생하지 않았다는 것이므로 소켓 연결 성공..

//서버와 메세지를 주고받을 통로 구축

is=new DataInputStream(socket.getInputStream());

os=new DataOutputStream(socket.getOutputStream());

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

//서버와 접속이 끊길 때까지 무한반복하면서 서버의 메세지 수신

while(true){

try {

msg= is.readUTF(); //서버 부터 메세지가 전송되면 이를 UTF형식으로 읽어서 String 으로 리

//서버로부터 읽어들인 메시지msg를 TextView에 출력..

//안드로이드는 오직 main Thread 만이 UI를 변경할 수 있기에

//네트워크 작업을 하는 이 Thread에서는 TextView의 글씨를 직접 변경할 수 없음.

//runOnUiThread()는 별도의 Thread가 main Thread에게 UI 작업을 요청하는 메소드임.

runOnUiThread(new Runnable() {

@Override

public void run() {

// TODO Auto-generated method stub

text_msg.setText(msg);

}

});

//////////////////////////////////////////////////////////////////////////

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}//while

}//run method...

}).start();//Thread 실행..

break;

case R.id.btn_send_client: //서버로 메세지 전송하기...

if(os==null) return;   //서버와 연결되어 있지 않다면 전송불가..

//네트워크 작업이므로 Thread 생성

new Thread(new Runnable() {

@Override

public void run() {

// TODO Auto-generated method stub

//서버로 보낼 메세지 EditText로 부터 얻어오기

String msg= edit_msg.getText().toString();

try {

os.writeUTF(msg);  //서버로 메세지 보내기.UTF 방식으로(한글 전송가능...)

os.flush();        //다음 메세지 전송을 위해 연결통로의 버퍼를 지워주는 메소드..

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}//run method..

}).start(); //Thread 실행..

break;

}

}

}

   



네트워크 사용하기 위해서는 사용 권한(uses-permission)이 필요합니다.

여러분 프로젝트의 메니페스트 파일에 퍼미션을 추가합니다.


 AndroidManifest.xml

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

    package="com.kitesoft.socket"

    android:versionCode="1"

    android:versionName="1.0" >


    <uses-sdk

        android:minSdkVersion="8"

        android:targetSdkVersion="16" />

    

    <!-- 네트워크 작업을 위한 permission -->

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


    <application

        android:allowBackup="true"

        android:icon="@drawable/ic_launcher"

        android:label="@string/app_name"

        android:theme="@style/AppTheme" >

        <activity

            android:name=".MainActivity"

            android:label="@string/app_name" >

            <intent-filter>

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


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

            </intent-filter>

        </activity>

        

        <activity

            android:name=".ServerActivity"

            android:label="@string/title_activity_server" >

        </activity>

        

        <activity

            android:name=".ClientActivity"

            android:label="@string/title_activity_client" >

        </activity>

        

    </application>


</manifest>

 

반응형

+ Recent posts