공부/Java

웹 소켓(Web Socket) 서버로 채팅하기

Egomi 2017. 5. 8. 12:49

Java에서는 WebSocket을 이용해 웹 소켓 서버를 구축할 수 있다.

ChatServerEndPoint.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
package com.newlecture.web.service;
 
import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
 
import javax.websocket.EndpointConfig;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
 
import com.google.gson.Gson;
 
//소켓 ip(건물번호)+port(사서함번호)+web
@ServerEndpoint("/resource/chatserver")
public class ChatServerEndPoint {
   
    private static Set<Session> clients;
    
    //static 생성자로 생성해줌.
    static{
        //누군가 쓰레드를 읽고 있을 때, 조작을 할 수 없게 Lock을 걸 수 있는 컬렉션을 이용해야함.
        //Set 생성 시, 동기화된 컬렉션을 생성해줌. => synchronizedSet()이용
        clients = Collections.synchronizedSet(new HashSet<Session>());
        
    }
    
   @OnOpen
   public void onOpen(Session session, EndpointConfig config){
      System.out.println(session.toString()+"Connected");
      clients.add(session);
   }
   
   @OnMessage
   public void onTextMessage(Session session, String data) throws IOException{
      
      //Gson.fromJson : JSON을 Java의 Object로 변환해준다.
      //id와 msg가 담긴 JSON을 담을 Object형이 없으므로, ChatData라는 Object를 하나를 만들어준다.
      ChatData chatData = new Gson().fromJson(data, ChatData.class);
      System.out.println("id"+chatData.getId()+"msg:"+chatData.getMsg());
      
      for(Session s:clients)
          s.getBasicRemote().sendText(data);
   }
   
   @OnClose
   public void onClose(Session session){
      System.out.println("클라이언트 접속이 해제 되었습니다.");
      clients.remove(session);
      System.out.println(session.toString()+"DisConnected");
   }
   
}
cs

@ServerEndPoint 어노테이션으로 서버 url을 매핑해준다. 여기선 /resource/chatserver로 매핑하였다.

 private static Set<Session> clients;

session을 Collection(Set, List, Map) 중에서 Set 컬렉션에 넣어준다.

참고 : List는 중복 허용되는 순서가 있는 집합, Set은 중복 허용없는 순서 유지 없는 집합, Map은 key-value의 집합)

    //static 생성자로 생성해줌.
    static{
        //누군가 쓰레드를 읽고 있을 때, 조작을 할 수 없게 Lock을 걸 수 있는 컬렉션을 이용해야함.
        //Set 생성 시, 동기화된 컬렉션을 생성해줌. => synchronizedSet()이용
        clients = Collections.synchronizedSet(new HashSet<Session>());
        
    }

static 생성자는 요청 시 매번 생성되는 인스턴스 생성자와 달리, 한 번 생성되면 다시는 생성되지 않는다.

여기서는 요청된 Session을 저장할 목적이므로, 요청마다 생성되면 기존의 session이 날라가버리니 Static생성자를 이용한다.

Collections.synchronizedSet이란, Session별 쓰레드 생성 시, 누군가 R(Read)하고 있을  때 CUD(Create,Update,Delete)를 불가능하게 하는 동기적 특성을 갖게하는 것이다. 다시 말해, 동시 접근 불가능하게 해주는 컬렉션이다.!!!

여기선 누군가 session을 조작할 때, 다른 사람이 접근하면 안되므로, 이 기능을 사용한다.

@onOpen마다 접속자 정보를 clients의 컬렉션에 저장한다. 마찬가지로 @onClose되면 clients로부터 해당 접속자를 제거해준다.

   @OnMessage
   public void onTextMessage(Session session, String data) throws IOException{
      
      //Gson.fromJson : JSON을 Java의 Object로 변환해준다.
      //id와 msg가 담긴 JSON을 담을 Object형이 없으므로, ChatData라는 Object를 하나를 만들어준다.
      ChatData chatData = new Gson().fromJson(data, ChatData.class);
      System.out.println("id"+chatData.getId()+"msg:"+chatData.getMsg());
      
      for(Session s:clients)
          s.getBasicRemote().sendText(data);
   }

@onTextMessage는 데이터를 받았을 때, 이를 처리하는 메소드이다.

현재 data는 Json 형식으로 날라가고 있는데, 이를 java의 Object로 변환하기 위해 GSON을 쓴다.

GSON? Object<->JSON 해주는 라이브러리이다.

GSON.fromJSON(JSON 명, 객체 명.class )  : JSON -> Object로 명시한 Object로 바꿔 반환해준다.