해당 포스트는 "안드로이드 통신+보안 프로그래밍" 책의 내용을 요약한 것이다.



※ 안드로이드 채팅 서버 소켓 프로그램 구현

: 클라이언트에서 "to:클라이언트 아이디" + "메시지" 형태로 텍스트를 입력 후 보내면 해당 클라이언트 아이디를 가진 스마트폰으로 텍스트를 보내는 예제이다.  클라이언트 아이디는 서버에 접속한 스마트폰의 IP D클래스로 하고 만약 클라이언트가 "to~" 형식으로 보내지 않을 경우 모든 클라이언트에게 메시지가 보내진다. 만약 클라이언트가 quit라는 메시지를 입력하면 서버와의 접속을 종료한다. 

안드로이드 클라이언트 프로그램은 이전 포스트에 사용했던 클라이언트 프로그램을 사용하면 된다.

public class ChattingServerActivity extends Activity {
    ....변수 선언

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (serverThread != null) {
            new Thread() {
                @Override
                public void run() {
                    serverThread.shutdown();
                    serverThread = null;
                }
            }.start();
        }
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        ...변수 초기화 및 UI 설정
    	
        start.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    port = Integer.parseInt(eport.getText().toString());
                } catch (NumberFormatException e) {
                    port = 6000;
                }

                if (serverThread == null) {
                    try {
                        serverThread = new ServerThread();
                        serverThread.start();
                        text.setText("Server Thread를 시작하였습니다.\n");
                        Toast.makeText(v.getContext(), "서비스가 시작되었습니다.",
                                       Toast.LENGTH_SHORT).show();
                        start.setEnabled(false);
                        finish.setEnabled(true);
                    } catch (IOException e) {
                        text.setText("Server Thread를 시작하지 못했습니다." + e.toString());
                    }
                } else {
                    Toast.makeText(v.getContext(), "서비스가 실행되고 있습니다.",
                            Toast.LENGTH_SHORT).show();
                }
            }
        });

        finish.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (serverThread != null) {
                    new Thread() {
                        @Override
                        public void run() {
                            serverThread.shutdown();
                            serverThread = null;
                        }
                    }.start();
                }
                text.setText("서비스를 종료합니다.\n");
                start.setEnabled(true);
                finish.setEnabled(false);
                Toast.makeText(v.getContext(), "서비스를 종료합니다.", Toast.LENGTH_SHORT).show();
            }
        });

        mHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case MSG_ID:
                        text.append((String) msg.obj + "\n");
                        break;
                    default:
                        break;
                }
                super.handleMessage(msg);
            }
        };
    }

    public class ServerThread extends Thread {
        private final HashMap<Integer, PrintWriter> hm;
        private final ServerSocket socket;

        public ServerThread() throws IOException {
            super();
            socket = new ServerSocket(port);
            socket.setSoTimeout(3000);
            hm = new HashMap<Integer, PrintWriter>();
            threadList = new ArrayList<ChatThread>();
            lock = new ReentrantLock();
        } // 생성자

        @Override
        public void run() {
            while (!Thread.currentThread().isInterrupted()) {
                try {
                    ChatThread thread = new ChatThread(socket.accept(), hm);
                    thread.start();
                    lock.lock();
                    threadList.add(thread);
                    lock.unlock();
                } catch (InterruptedIOException e) {
                } catch (SocketException e) {
                    return; 
                } catch (IOException e) {
                    shutdown();
                    e.printStackTrace();
                    return;
                }
            }
        }

        public void shutdown() {
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            clearlist();
            Thread.currentThread().interrupt();
        }

        private void clearlist() {
            if (!threadList.isEmpty()) {
                lock.lock();
                for (int i = 0; i < threadList.size(); ++i) {
                    ChatThread t = threadList.get(i);
                    t.quit();
                    t.interrupt();
                }
                lock.unlock();
            }
        }
    }

	class ChatThread extends Thread {
        private Socket sock;
        private Integer id;
        private BufferedReader br;
        private PrintWriter opw;
        private final HashMap<Integer, PrintWriter> hm;

        public ChatThread(Socket sock, HashMap<Integer, PrintWriter> hm) {
                this.sock = sock;
                this.hm = hm;
                try {
                    opw = new PrintWriter(new OutputStreamWriter(sock.getOutputStream()));
                    br = new BufferedReader(new InputStreamReader(sock.getInputStream()));
                    id = Integer.parseInt(HostId(sock.getRemoteSocketAddress().toString()));

                    synchronized (this.hm) {
                        this.hm.put(this.id, opw);
                    }
                    broadcast(id + "님이 접속하였습니다.");
                    Message m = new Message();
                    m.what = MSG_ID;
                    m.obj = ("접속한 사용자의 아이디는 " + id + " 입니다.");
                    mHandler.sendMessage(m);
//                } catch (NumberFormatException ex) {
                } catch (Exception e) {
					e.printStackTrace();
                }
        }

        @Override
        public void run() {
                try {
                    String line = null;
                    while ((line = br.readLine()) != null) {
                        if (line.equals("quit"))
                            break;
                        if (line.indexOf("to:") == 0) {
//                        int start = line.indexOf("to:") + 1;            
                            sendmsg(line.substring(3));
                        } else
                            broadcast(id + "가 보낸 메시지는 '" + line + "' 입니다.");
                    }
                } catch(InterruptedIOException e) {
                } catch (Exception ex) {
                } finally {
                    synchronized (this.hm) {
                        this.hm.remove(this.id);
                    }
                    broadcast(id + " 님이 접속 종료하였습니다.");
                    Message m = new Message();
                    m.what = MSG_ID;
                    m.obj = (id + " 님이 접속 종료하였습니다.");
                    mHandler.sendMessage(m);
                    try {
                        lock.lock();
                        threadList.remove(this);
                        lock.unlock();
                        if (sock != null) {
                            sock.close();
                            sock = null;
                        }
                        if (br != null) {
                            br.close();
                            br = null;
                        }
                        if (opw != null) {
                            opw.close();
                            opw = null;
                        }
                    } catch (Exception e) {
						e.printStackTrace();
                    }
                }
        }

        public void sendmsg(String msg) {
                int end = msg.indexOf(" ", 1);
                if (end != -1) {
                    try {
                        Integer to = Integer.parseInt(msg.substring(0, end));
                        String msg2 = msg.substring(end + 1);
                        Object obj = hm.get(to);
                        if (obj == null) {
                            opw.println(msg + "를 해석할 수 없습니다. ");
                            opw.flush();
                        } else {
                            PrintWriter pw = (PrintWriter) obj;
                            pw.println(id + " 님이 메시지를 보냈습니다. " + msg2);
                            pw.flush();
                        }
                    } catch (NumberFormatException ex) {
                        broadcast(id + "가 보낸 메시지는 'to:" + msg + "'로 잘못되어 있습니다.");
                    }
                }
        } // sendmsg

        public void broadcast(String msg) {
                synchronized (hm) {
                    Collection<PrintWriter> collection = hm.values();
                    Iterator<PrintWriter> iter = collection.iterator();
                    while (iter.hasNext()) {
                        PrintWriter pw = iter.next();
                        pw.println(msg);
                        pw.flush();
                    }
                }
        } // broadcast

        private String HostId(String host) {
                int start = host.lastIndexOf(".");
                int end = host.lastIndexOf(":");
                String ca = host.substring(start + 1, end);
                return ca;
        }

        public void quit() {
                if (sock != null) {
                    try {
                        sock.close();
                        sock = null;
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
        }
    }
}


+ Recent posts