티스토리 뷰

개발자 배배/Android

[멀티채팅] 4. Server 구현하기

사연있는 배배 2016. 5. 31. 01:28

 1) 프로세스를 따라가 봅시다
 
  : Server에서는 새로운 사용자가 접속해서 Socket이 반환되면, 바로 ServerReceiver라는 thread를 돌리게 됩니다. 
  해당 thread에서 하는 일은 여러가지가 있습니다. 
     1) InputStream으로부터 name과 msg를 받습니다. 
     2) HashMap에 (name, OutputStream) 정보를 담아 놓습니다. 
           -> Q) 왜 하필 OutputStream정보를 담아 놓는걸까요? 
                : sendToAll()를 보시면 알수 있는데, 현재 접속된 사용자들을 한번씩 다 조회하면서 각각의 OutputStream으로 msg를 뿌려주기 위함입니다. 

 

 

 

 

 

 2) 코드

 

JavaMultiChatServer.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
 
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
 
 
public class JavaMultiChatServer
{
    HashMap clients;
 
    JavaMultiChatServer()
    {
        clients = new HashMap();
        Collections.synchronizedMap(clients);
    }
 
    public void start()
    {
        ServerSocket serverSocket = null;
        Socket socket = null;
 
        try
        {
            serverSocket = new ServerSocket(7777);
            System.out.println("서버가 시작되었습니다.");
 
            // 이 무한루프는 사용자를 계속 받기위한 무한루프 입니다. 사용자마다 소켓 1개씩 할당.
            while(true)
            {
                socket = serverSocket.accept();
                System.out.println("[" + socket.getInetAddress() + "," + socket.getPort() + "]"
                        + "에서 접속하셨습니다.");
 
                // 새로운 사용자가 잡속을 시도할때마다 계속 thread를 생성합니다. (main thread가 일을 다 처리하기 힘드니까, 각각 thread에 분업시킵니다.)
                ServerReceiver thread = new ServerReceiver(socket);
                thread.start();
            }
 
        }catch (Exception e)
        {
            e.printStackTrace();
        }
    }
 
    public static void main(String[] args)
    {
        new JavaMultiChatServer().start();
 
    }
 
    /**
     * 모든 사용자에게 msg를 뿌려주는 메소드
     * @param msg
     */
    public void sendToAll(String msg)
    {
        Iterator it = clients.keySet().iterator();
 
        while(it.hasNext())
        {
            try
            {
                // iterator로 하나씩 조회하면서, client.get() 을 통해 해당 value(저장된 OutputStream 값) 을 빼옵니다.
                DataOutputStream out = (DataOutputStream) clients.get(it.next());
 
                out.writeUTF(msg); // 해당 outputStream으로 전달받은 msg를 뿌려줍니다.
                out.flush();
 
            }catch (IOException e) { }
        }
    }
 
 
 
    /**
     *  얘는 새로운 사용자가 접속을 시도할때마다 불리는 thread입니다.
     */
    class ServerReceiver extends Thread
    {
        Socket socket;
        DataInputStream in;
        DataOutputStream out;
 
        // contsructor에서 받아온 socket정보를 이용하여 새로운 사용자와의 연결을 setting합니다.
        ServerReceiver(Socket socket)
        {
            this.socket = socket;
 
            try
            {
                in = new DataInputStream(socket.getInputStream());
                out = new DataOutputStream(socket.getOutputStream());
 
            }catch (IOException e){}
        }
 
        @Override
        public void run()
        {
            String name = "";
            // 1. 먼저, 사용자의 이름과 outputStream정보를 hashmap에 추가합니다.
            try
            {
                name = in.readUTF(); // 이름을 먼저 받아놓습니다. 왜냐면 hashmap에 먼저 등록을 해놓기 위해서! (Client측에서도 그렇게 해놨습니다. 이름먼저 보내고 내용보내기로.)
                System.out.println("#" + name + "님 접속하셨군요."); // 테스트용
                sendToAll("#"+name+"님이 들어오셨습니다.");
 
                // hashMap에 name-OutputStream 정보를 추가해줍니다! 왜 하필 OutputStream이냐구요? sendToAll()를 보면 알수 있어요!
                clients.put(name, out);
                System.out.println("현재 접속자 수 : " + clients.size() + "명");
 
 
 
                while(in != null
                {
                    sendToAll(in.readUTF());
                }
 
            }catch(IOException e) { }
            finally
            {
                sendToAll("#"+ name + "님이 나가셨습니다.");
 
                clients.remove(name);
 
                System.out.println("[" + socket.getInetAddress() + "," + socket.getPort() + "]"
                        + "에서 접속을 종료하셨습니다.");
                System.out.println("현재 접속자 수 : " + clients.size() + "명");
 
 
            }
 
        }
 
    }
}
 
cs

 

+ ) 사실은 이 코드들은 성능에 최적화된 코드들이기보다, 초심자에게 좀더 친근할법한 코드, 문법을 사용한 경향이 있습니다. 

그래서 다음 포스트에서는 몇가지 리팩토링을 하면서, 어떤 것이 어떻게 개선 되었는지를 함께 공부할 예정입니다!

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
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
글 보관함