네트워크에서 두 프로그램 간의 양방향 통신의 끝단이다. 오늘날의 컴퓨터 통신은 대부분이 인터넷 프로토콜 기반이므로 대부분의 네트워크 소켓이 인터넷 소켓이다.
Spring에서 소켓은 접속까지만 Http프로토콜을 사용하며 이후에는 별도의 Websocket 프로토콜로 송신을 한다.
<!-- Spring WebSocket -->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-websocket -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>${org.springframework-version}</version>
</dependency>
<!-- jackson bind -->
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
</dependency>
Spring Websocket 사용을 위한 의존성 주입. JSON 형태로 받은 데이터를 Java 객체로 옮기기 위한 jackson-bind 라이브러리 또한 pom.xml에 기입해준다.
<!-- WebSocket 요청 시 핸들러 클래스와 연결하기 -->
<beans:bean id="chatHandler" class="소켓 통신용 클래스를
작성한 패키지+클래스명"/>
<websocket:handlers>
<!-- 웹소켓 요청을 처리할 bean 지정 -->
<websocket:mapping handler="chatHandler" path="/chat"/>
<!--/chat으로 온 웹소켓 요청을 처리 -->
<websocket:handshake-interceptors>
<!-- interceptor : http 통신 req, resp 가로채는 역할
handshake-interceptors :
요청 관련 데이터 중 HttpSession(로그인 정보, 채팅방 번호)을 가로채서
WebSocketSession에 넣어주는 역할
-->
<beans:bean class="org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor"/>
</websocket:handshake-interceptors>
<!-- SockJS 라이브러리를 이용해서 만들어진 웹소켓 객체임을 인식 -->
<websocket:sockjs></websocket:sockjs>
</websocket:handlers>
</beans:beans>
Websocket 사용을 위한 클래스를 구현해준다.
public class ChatWebsocketHandler extends TextWebSocketHandler{
@Autowired
private ChatService service;
/*
* WebSocketHandler 인터페이스 : 웹소켓을 위한 메소드를 지원하는 인터페이스
-> WebSocketHandler 인터페이스를 상속받은 클래스를 이용해 웹소켓 기능을 구현
WebSocketHandler 주요 메소드
void handlerMessage(WebSocketSession session, WebSocketMessage message)
- 클라이언트로부터 메세지가 도착하면 실행
void afterConnectionEstablished(WebSocketSession session)
- 클라이언트와 연결이 완료되고, 통신할 준비가 되면 실행
void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus)
- 클라이언트와 연결이 종료되면 실행
void handleTransportError(WebSocketSession session, Throwable exception)
- 메세지 전송중 에러가 발생하면 실행
----------------------------------------------------------------------------
TextWebSocketHandler : WebSocketHandler 인터페이스를 상속받아 구현한 텍스트 메세지 전용 웹소켓 핸들러 클래스
handlerTextMessage(WebSocketSession session, TextMessage message)
- 클라이언트로부터 텍스트 메세지를 받았을때 실행
*
* */
// Set<WebSocketSession>을 왜 만든 이유?
// - WebSocketSession == 웹소켓에 연결된 클라이언트 세션
// -> 세션을 통해서 누가 연결했는지 알 수 있다.
// -> WebSocketSession 모아둔다?
// == 현재 웹소켓에 연결되어있는 모든 클라이언트를 알 수 있다.
// -> Set을 분석해서 원하는 클라이언트를 찾아서 메세지를 전달할 수 있다.
private Set<WebSocketSession> sessions
= Collections.synchronizedSet(new HashSet<WebSocketSession>());
// synchronizedSet : 동기화된 Set반환
// -> 멀티스레드 환경에서 하나의 컬렉션 요소에 여러 스레드가 접근하면 충돌이 발생할 수 있으므로
// 동기화(충돌이 안 나도록 줄세움)를 진행
// 클라이언트와 연결이 완료되고, 통신할 준비가 되면 수행
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
// WebSocketSession : 웹소켓에 접속/요청한 클라이언트의 세션
System.out.println(session.getId() + "연결됨");
sessions.add(session);
// WebSocketSession을 Set에 추가
}
// 클라이언트로부터 텍스트 메세지를 전달 받았을 때 수행
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
// TextMessage : 웹소켓을 이용해 텍스트로 전달된 메세지가 담겨있는 객체
// payload : 전송되는 데이터
// message.getPayload()
System.out.println("전달된 메세지 : " + message.getPayload());
// Jackson 라이브러리 : Java에서 JSON을 다루기 위한 라이브러리
// Jackson-databind 라이브러리 :
// ObjectMapper 객체를 이용해서
// JSON 데이터를 특정 VO 필드에 맞게 자동 매핑
ObjectMapper objectMapper = new ObjectMapper();
ChatMessage chatMessage = objectMapper.readValue(message.getPayload(), ChatMessage.class);
// 시간 세팅
chatMessage.setCreateDate(new Date(System.currentTimeMillis()));
System.out.println(chatMessage);
// 채팅 메세지 DB삽입
int result = service.insertMessage(chatMessage);
if(result>0) {
// 같은 방에 접속 중인 클라이언트에게만 메세지 보낸기
// -> Set<WebSocketSession>에서 같은 방 클라이언트 골라내기
for(WebSocketSession s : sessions ) {
// WebSocketSession == HttpSession(로그인 정보, 채팅방 번호)을 가로챈 것
int chatRoomNo = (Integer)s.getAttributes().get("chatRoomNo");
// WebSocketSession에 담겨있는 채팅방 번호와
// 메세지에 담겨있는 채팅방 번호가 같을 경우
// 같은 방 클라이언트다.
if(chatRoomNo == chatMessage.getChatRoomNo()) {
// 같은 방 클라이언트에게 JSON 형식 메세지를 보냄
s.sendMessage(new TextMessage(new Gson().toJson(chatMessage)));
}
}
}
}
// 클라이언트와 연결이 종료되면 수행
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
sessions.remove(session);
// 웹소켓 연결이 종료되는 경우
// 종료된 WebSocketSession을 Set에서 제거한다.
}
}