ㅇ.ㅇ
[WebSocket] Error - The remote endpoint was in state [TEXT_FULL_WRITING] which is an invalid state for called method 본문
[WebSocket] Error - The remote endpoint was in state [TEXT_FULL_WRITING] which is an invalid state for called method
yun_ 2023. 5. 20. 16:59
소켓통신을 구현하여 broadcasting으로 클라이언트에게 데이터를 보내는 중 json 형식이 깨지는 것을 발견하였고, 그것을 수정하는 과정에서 에러가 발생하였다. 막상 타입문제는 아니었지만 함께 적어본다.
상황
웹소켓에서 스케줄링을 하면서 브로드캐스팅으로 계속 데이터를 보내고 있는 상황이다. 그렇지만 여러 스케줄러가 하나의 'broadcast' 메소드를 호출하면서 충돌이 난 것을 확인하게 되었다.
에러 내용
The remote endpoint was in state [TEXT_FULL_WRITING] which is an invalid state for called method
문제 원인
스레드 동기화
해당 에러는 원격서비스가 현재 텍스트 작성중인 상태로 '호출하려는 메서드에는 유효하지 않은 상태'인 경우에 발생한다. 즉 이미 어떠한 상태에 있으므로 다시 메서드가 호출을 하지 않는다는 것.
// 수정 전 코드
public static void broadcast(Session session, Object object) throws JsonProcessingException {
try {
if (session != null && session.isOpen()) {
session.getBasicRemote().sendText(object);
}
} catch (Exception e) {
e.printStackTrace();
}
}
쉽게말하면, 에러가 발생하는 이유 자체가 여러 스레드가 동시에 session.getBasicRemote().sendText(object) 메서드를 호출하는 동안, 해당 세션 객체가 이미 '텍스트 작성중인 상태'에 있어서 호출된 메서드에 대한 유효하지 않은 상태로 간주되기 때문이다.
이런 문제를 해결하기 위해서는 '세션 객체 동기화'를 해주어야 한다. 세션 객체를 동기화해주면 여러 스레드나 프로세스가 동시에 하나의 세션을 호출하지 못하도록 제어할 수 있다.
해결 방법
이 문제를 해결하기 위해서는 lock이라는 객체를 사용해서 동기화를 수행한다.
모든 스레드는 lock 객체에 대한 동기화를 기다려야하므로, 여러 세션 객체에 대한 동기화 문제를 방지할 수 있다.
// 수정 후 코드
private static final Object lock = new Object();
public static void broadcast(Session session, Object object) throws JsonProcessingException {
try {
synchronized (lock) { // lock 객체를 사용한 동기화
if (session != null && session.isOpen()) {
session.getBasicRemote().sendText(json);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
- synchronized (lock) {... } : lock 객체를 사용해서 동기화된 블록을 생성
- 여러 스레드가 동시에 sendText() 메서드 호출해도, lock 객체를 사용한 동기화로 인해 하나의 세션에 대한 작업이 완료 된 후에 다음 세션으로 이동
+ ) Java String 타입을 Json형식으로 변환
브로드캐스팅하는 메소드로 데이터는 String 타입으로 받아와진다.
예 ) {name=admin}
그렇지만 클라이언트 쪽에다가는 아래와 같이 json 형식으로 변환해서 보내야했다.
예 ) {"name":"admin"}
그래서 아래와 같은 식으로 Jackson 라이브러리의 ObjectMapper를 사용하여 Java 객체를 Json 문자열로 직렬화하였다.
- ObjectMapper : Java 객체와 Json 데이터 간의 변환 처리
- writeValueAsString() : 주어진 객체를 Json 문자열로 직렬화
ObjectMapper objectMapper = new ObjectMapper();
String json = objectMapper.writeValueAsString(object);
session.getBasicRemote().sendText(json);
'Error' 카테고리의 다른 글
[Build] CreateProcess error=2, 지정된 파일을 찾을 수 없습니다 (0) | 2024.12.12 |
---|---|
[Gradle] Multiple build operations failed. Could not move temporary workspace (0) | 2024.11.29 |
[Tomcat] 톰캣 다중 구동환경 시 로그인 끊김 현상 / jsessionid 충돌 (0) | 2023.04.06 |
[Java] Error - Invalid property 'maxWait' of bean class (0) | 2023.03.29 |
[Java] Error - Illegal hexadecimal character q at index 0 (0) | 2023.03.23 |