국비/Project-2 쇼핑몰

2023.06.21 100일차 Team Project WebSocket

춘핑이 2023. 6. 26. 10:08

100일차

웹소켓 제거

채팅 닫기 버튼 누를시 웹소켓 제거하고 연결끊기
연결끊을시 어드민 쪽에 연결이 끊겻음을알리고 어드민소켓도 끊기
연결해제시 ajax요청을 통해 list에서 채팅방 삭제하기

이전 까지 웹소켓을 처리하던 중 문제가 발생했다.
웹소켓 sc.onclose()즉 닫앗을때 상태가 처리가 되어있는데 이게 닫히질 않는다.
sockethandler에서도 종료후 처리가 있는데 닫히질 않는다.

@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
    //소켓 종료
    if(rls.size() > 0) { //소켓이 종료되면 해당 세션값들을 찾아서 지운다.
        for(int i=0; i<rls.size(); i++) {
            rls.get(i).remove(session.getId());
        }
    }
    super.afterConnectionClosed(session, status);
}

프론트단과 백엔드 모두다 닫는 처리를 해줘야한다.
즉 클라이언트측에서 웹소켓을 닫고 서버측에서 세션을 종료시켜줘야한다.

1. sockethandler

닫는 요청이 오면 session.close();를 통해 웹소켓의 세션을 종료시켜주는 코드를 추가했다.

@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
    session.close();
    // 소켓 종료
    if (roomList.size() > 0) { // 소켓이 종료되면 해당 세션값들을 찾아서 지운다.
        for (int i = 0; i < roomList.size(); i++) {
            roomList.get(i).remove(session.getId());
        }
    }
    super.afterConnectionClosed(session, status);
}

2. js

채팅창 닫기 버튼을 누르면 웹소켓 객체의 close메소드를 이용해서 닫는다.

$("#chatCloseBtn").click(function(){
    ws.close();
    console.log(ws.readyState);
    ws = null;
});

WebSocket의 readyState 속성은 현재 WebSocket 연결의 상태를 나타내는 정수 값이다.
readyState 값은 다음과 같은 네 가지 상태 중 하나일 수 있다.

0 (WebSocket.CONNECTING): 연결이 수립 중인 상태. 웹 소켓 객체가 생성되고 연결을 시도 중인 상
1 (WebSocket.OPEN): 연결이 열린 상태. 웹 소켓 연결이 성공적으로 수립되었으며 데이터를 주고받을 수 있는 상태.
2 (WebSocket.CLOSING): 연결이 닫히는 중인 상태. 웹 소켓 연결이 종료되기 전에 닫히는 프로세스가 진행 중인 상태.
3 (WebSocket.CLOSED): 연결이 닫힌 상태. 웹 소켓 연결이 완전히 종료되었고 더 이상 데이터를 주고받을 수 없는 상태.
즉, readyState 값이 2인 경우는 웹 소켓 연결이 닫히는 과정인 것을 나타낸다. 연결이 완전히 닫힌 후에는 readyState 값이 3이 된다.

따라서 위 코드를 통해 콘솔에 찍으면 닫히는 중이라 2가 찍히게 된다.
이렇게 닫기 요청을 해줘야 닫히는 것이엇고 내가 참조하던 블로그엔 닫기를 하지 않아서 스스로 혼돈이 오고 있엇고 웹소켓자원을 계속 열어두는 불상사가 발생하고 있던 것이다.

3. admin도닫기

클라이언트 측에서 일방적으로 닫는 것이기 때문에 admin은 닫힌지를 모른다.
그래서 클라이언트 측에서
메시지로

let data = {
    type: "close",
    // ... 기타 필요한 데이터 ...
  };
  ws.send(JSON.stringify(data));

닫앗다는 메시지를 보내고 닫으면될듯하다는 생각이 들었다.
클라이언트가 닫았다는 메시지를 받으면 같이 ws.close()를 해줄 것이다.

3.1 클라이언트

chatCloseBtn을 누르면 이 함수를 발생시킬 것이다.
기존에 메시지를 보내던 것에서 type을 close로하고 보낸 것이다.
보내면서 웹소켓을 닫는다.

function disconnect() {
    if (ws !== null) {
        let data = {
            type: "close",
            roomNumber: roomNumber,
            sessionId: $("#sessionId").val(),
            userName: customerId,
            msg: $("#textMessage").val()
        }
        ws.send(JSON.stringify(data));
        ws.close();
        ws = null;
    }
}

3.2 admin

메시지를 받앗을때 타입이 close라면 ws.close()를 통해서 닫아준다.

ws.onmessage = function(data) {
    let msg = data.data;
    if (msg != null && msg.trim() != '') {
        let serverJson = JSON.parse(msg);
        if (serverJson.type === "getId") {
            let sId = serverJson.sessionId != null ? serverJson.sessionId : "";
            if (sId != '') {
                $("#sessionId").val(sId);
            }
        } else if (serverJson.type === "message") {
            if (serverJson.sessionId === $("#sessionId").val()) {
                $("#messageTextArea").append("<div class='me'>관리자: " + serverJson.msg + "</div>");
            } else {
                $("#messageTextArea").append("<div class='admin'>고객님: " + serverJson.msg + "</div>");
            }
        } else if (serverJson.type === "close"){
            ws.close();
            ws = null;
        } else {
            console.warn("unknown type!")
        }
    }
}

3.3 방목록에서 삭제하기

순회중에 삭제하면 index오류나기때문에 roomList.iterator를얻어서삭제해야한다.

@ResponseStatus(HttpStatus.OK)
@PostMapping("deleteRoom")
@ResponseBody
public void deleteRoom(@RequestParam int roomNumber) {
    chatService.removeRoom(roomNumber);
}

@Override
public void removeRoom(int roomNumber) {
    Iterator<ChatRoom> iterator = roomList.iterator();
    while (iterator.hasNext()) {
        ChatRoom room = iterator.next();
        if (room.getRoomNumber() == roomNumber) {
            iterator.remove();
        }
    }
}

반복자를 얻어서 삭제해준다.

2023.06.21

너무 복잡하게 코드를 이리저리 왔다갓다 작성해서 정리가 잘되지 않는 느낌이다.
전체적으로 설명하게 하면 설명을 하겠지만 부분을 설명하는게 어렵다.
이 블로그를 와서 보고 있는 분들에게 너무 죄송할 따름이다.

하지만 발전하는게 즐겁고 이런 새로운 것을 만들고 동작하였을때의 기분이 참 좋은 것 같다.
모두가 좋은일만 가득하기를 바란다.