괴도군의 블로그

[Android] 채팅서버 / 채팅앱 소스입니다. 본문

#프로그래밍/Android

[Android] 채팅서버 / 채팅앱 소스입니다.

괴도군 2016. 12. 2. 14:35
반응형

 

 

 

안녕하세요 괴도입니다.

떠돌아다니는 pc버전 자바채팅소스를 앱으로 만들어봤습니다.

소켓통신 그대로 핸드폰에서도 서버를 열고 채팅이 가능합니다

테스트는 공유기환경에서 해주셔야합니다.

ip가져오는부분부터 wifi만 가능하도록 해놨습니다.

 

하나의폰으로도 채팅테스트가 가능합니다.

( 서버 / 클라이언트 )

 

AndroidManifest.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.t5online.chat" >
 
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
 
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme"
        >
 
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:theme="@android:style/Theme.NoTitleBar"
            android:windowSoftInputMode="adjustPan"
            android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
 
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
 
</manifest>
 
cs

 

MainActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
package com.t5online.chat;
 
import android.app.Activity;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.DhcpInfo;
import android.net.NetworkInfo;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
 
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
 
public class MainActivity extends Activity implements View.OnClickListener {
 
    private static final int SERVER_TEXT_UPDATE = 100;
    private static final int CLIENT_TEXT_UPDATE = 200;
 
    private Button serverCreateButton;//서버열기
    private Button serverTransButton;//서버텍스트전송
    private Button serverJoinButton;//서버접속
    private Button clientTransButton;//클라전송
 
    private TextView serverIpText;//서버아이피확인
    private TextView serverText;//서버채팅창
    private TextView clientText;//클라채팅창
    private EditText joinIpText;//클라접속아이피
    private EditText transServerText;
    private EditText transClientText;
 
 
    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msgg) {
            super.handleMessage(msgg);
            switch (msgg.what) {
                case SERVER_TEXT_UPDATE: {
                    serverMsg.append(msg);
                    serverText.setText(serverMsg.toString());
                }
                break;
                case CLIENT_TEXT_UPDATE: {
                    clientMsgBuilder.append(clientMsg);
                    clientText.setText(clientMsgBuilder.toString());
                }
                break;
 
            }
        }
    };
    //서버세팅
    private ServerSocket serverSocket;
    private Socket socket;
    private String msg;
    private StringBuilder serverMsg = new StringBuilder();
    private StringBuilder clientMsgBuilder = new StringBuilder();
    private Map<String, DataOutputStream> clientsMap = new HashMap<String, DataOutputStream>();
 
    //클라세팅
    private Socket clientSocket;
    private DataInputStream clientIn;
    private DataOutputStream clientOut;
    private String clientMsg;
    private String nickName;
 
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        serverCreateButton = (Button) findViewById(R.id.server_create_button);
        serverTransButton = (Button) findViewById(R.id.trans_server_button);
        serverJoinButton = (Button) findViewById(R.id.server_join_button);
        clientTransButton = (Button) findViewById(R.id.trans_client_button);
        serverIpText = (TextView) findViewById(R.id.server_ip_text);
        serverText = (TextView) findViewById(R.id.server_text);
        clientText = (TextView) findViewById(R.id.client_text);
        joinIpText = (EditText) findViewById(R.id.join_ip_text);
        transServerText = (EditText) findViewById(R.id.trans_server_text);
        transClientText = (EditText) findViewById(R.id.trans_client_text);
 
        serverCreateButton.setOnClickListener(this);
        serverTransButton.setOnClickListener(this);
        serverJoinButton.setOnClickListener(this);
        clientTransButton.setOnClickListener(this);
 
    }
 
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.server_create_button: {
                serverIpText.setText(getLocalIpAddress() + ":7777");
                serverCreate();
            }
            break;
            case R.id.trans_server_button: {
                String msg = "서버 : " + transServerText.getText().toString() + "\n";
                serverMsg.append(msg);
                serverText.setText(serverMsg.toString());
                sendMessage(msg);
                transServerText.setText("");
            }
            break;
            case R.id.server_join_button: {
                joinServer();
            }
            break;
            case R.id.trans_client_button: {
                String msg = nickName + ":" + transClientText.getText() + "\n";
//                clientMsgBuilder.append(msg);
//                clientText.setText(clientMsgBuilder.toString());
                try {
                    clientOut.writeUTF(msg);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                transClientText.setText("");
            }
            break;
 
        }
    }
 
    public String getLocalIpAddress() {
        WifiManager wifiMgr = (WifiManager) getSystemService(WIFI_SERVICE);
        WifiInfo wifiInfo = wifiMgr.getConnectionInfo();
        int ip = wifiInfo.getIpAddress();
        String ipAddress = String.format("%d.%d.%d.%d"
                , (ip & 0xff)
                , (ip >> 8 & 0xff)
                , (ip >> 16 & 0xff)
                , (ip >> 24 & 0xff));
        return ipAddress;
    }
 
    public void joinServer() {
        if(nickName==null){
            nickName="스마트폰";
        }
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    clientSocket = new Socket(joinIpText.getText().toString(), 7777);
                    Log.v("""클라이언트 : 서버 연결됨.");
 
                    clientOut = new DataOutputStream(clientSocket.getOutputStream());
                    clientIn = new DataInputStream(clientSocket.getInputStream());
 
                    //접속하자마자 닉네임 전송하면. 서버가 이걸 닉네임으로 인식을 하고서 맵에 집어넣겠지요?
                    clientOut.writeUTF(nickName);
                    Log.v("""클라이언트 : 메시지 전송완료");
 
                    while (clientIn != null) {
                        try {
                            clientMsg = clientIn.readUTF();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        handler.sendEmptyMessage(CLIENT_TEXT_UPDATE);
                    }
                } catch (UnknownHostException e1) {
                    e1.printStackTrace();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
        }).start();
    }
 
    public void serverCreate() {
        Collections.synchronizedMap(clientsMap);
        try {
            serverSocket = new ServerSocket(7777);
            new Thread(new Runnable() {
                @Override
                public void run() {
                    while (true) {
                        /** XXX 01. 첫번째. 서버가 할일 분담. 계속 접속받는것. */
                        Log.v("""서버 대기중...");
                        try {
                            socket = serverSocket.accept();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        Log.v("", socket.getInetAddress() + "에서 접속했습니다.");
                        msg = socket.getInetAddress() + "에서 접속했습니다.\n";
                        handler.sendEmptyMessage(SERVER_TEXT_UPDATE);
 
                        new Thread(new Runnable() {
                            private DataInputStream in;
                            private DataOutputStream out;
                            private String nick;
 
                            @Override
                            public void run() {
 
                                try {
                                    out = new DataOutputStream(socket.getOutputStream());
                                    in = new DataInputStream(socket.getInputStream());
                                    nick = in.readUTF();
                                    addClient(nick, out);
 
                                } catch (IOException e) {
                                    e.printStackTrace();
                                }
 
                                try {// 계속 듣기만!!
                                    while (in != null) {
                                        msg = in.readUTF();
                                        sendMessage(msg);
                                        handler.sendEmptyMessage(SERVER_TEXT_UPDATE);
                                    }
                                } catch (IOException e) {
                                    // 사용접속종료시 여기서 에러 발생. 그럼나간거에요.. 여기서 리무브 클라이언트 처리 해줍니다.
                                    removeClient(nick);
                                }
 
 
                            }
                        }).start();
                    }
                }
            }).start();
 
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
 
    public void addClient(String nick, DataOutputStream outthrows IOException {
        sendMessage(nick + "님이 접속하셨습니다.");
        clientsMap.put(nick, out);
    }
 
    public void removeClient(String nick) {
        sendMessage(nick + "님이 나가셨습니다.");
        clientsMap.remove(nick);
    }
 
    // 메시지 내용 전파
    public void sendMessage(String msg) {
        Iterator<String> it = clientsMap.keySet().iterator();
        String key = "";
        while (it.hasNext()) {
            key = it.next();
            try {
                clientsMap.get(key).writeUTF(msg);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
 
 
    @Override
    protected void onDestroy() {
        super.onDestroy();
        clientIn = null;
    }
}
 
cs

 

 

activity_main.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
<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:orientation="vertical"
    tools:context=".MainActivity"
    android:focusable="true"
    android:focusableInTouchMode="true">
 
    <Button
        android:id="@+id/server_create_button"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:text="서버열기" />
 
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="0.5"
        android:orientation="horizontal">
 
        <TextView
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="2"
            android:text="서버아이피" />
 
        <TextView
            android:id="@+id/server_ip_text"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="8"
 
            />
    </LinearLayout>
 
    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="4">
 
        <TextView
            android:id="@+id/server_text"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
 
    </ScrollView>
 
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:orientation="horizontal">
        <EditText
            android:id="@+id/trans_server_text"
            android:layout_width="0dp"
            android:layout_weight="8"
            android:layout_height="match_parent"
            android:hint="서버가 보내는채팅창"/>
        <Button
            android:id="@+id/trans_server_button"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="2"
            android:text="전송" />
    </LinearLayout>
 
 
    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="#000000" />
 
    <Button
        android:id="@+id/server_join_button"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:text="서버접속" />
 
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:orientation="horizontal">
 
        <TextView
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="2"
            android:text="접속아이피" />
 
        <EditText
            android:id="@+id/join_ip_text"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="8"
            android:hint="아이피 입력"
            />
    </LinearLayout>
 
 
    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="4">
 
        <TextView
            android:id="@+id/client_text"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
 
    </ScrollView>
 
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:orientation="horizontal">
        <EditText
            android:id="@+id/trans_client_text"
            android:layout_width="0dp"
            android:layout_weight="8"
            android:hint="클라이언트 채팅내용입력"
            android:layout_height="match_parent" />
        <Button
            android:id="@+id/trans_client_button"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="2"
            android:text="전송" />
    </LinearLayout>
 
 
 
</LinearLayout>
 
cs

 

테스트 스크린샷

 

 

예제 다운로드

github.com/jypDev/android_socket_chat/archive/master.zip

 

예제 github

github.com/jypDev/android_socket_chat

반응형
Comments