안드로이드에서 OkHttp로 WebSocket 연결하기

오리·2025년 1월 24일

웹소켓?

  • 웹소켓(WebSocket)은 클라이언트와 서버 간의 양방향 통신을 실시간으로 가능하게 하는 프로토콜로, 연결이 유지되는 동안 데이터를 지속적으로 주고받을 수 있음
  • 일반적인 HTTP 통신보다 네트워크 오버헤드가 적어 효율적인 데이터 전송에 적합

안드로이드에서 웹소켓 연결 방법

OkHttp 라이브러리 사용 이유

  • OkHttp는 Android에서 널리 사용되는 HTTP 라이브러리
  • 웹소켓 연결 및 상태 처리를 쉽게 구현할 수 있는 API를 제공

다른 방법들도 있긴 한데..

방법장점단점
OkHttp사용 편의성, 안정성, Android 최적화OkHttp 라이브러리에 의존
Java 표준추가 라이브러리 필요 없음구현 복잡성 증가, Android 프로젝트에서 최적화 부족
TyrusWebSocket 표준 API 준수설정이 복잡, 추가 라이브러리 필요
Socket.IO실시간 이벤트 기반 통신에 강점서버와 클라이언트 모두 Socket.IO 프로토콜을 사용해야 함
KtorKotlin 멀티플랫폼 지원, 경량화추가 학습 필요, Android 전용은 아님

WebSocketHandler

별도로 구성 하는 이유

  • REST 통신과는 성격이 완전히 다르므로 WebSocketHandler를 별도로 구성하는 것이 유지보수성과 확장성 측면에서 필수적
  • WebSocket은 연결 상태(Connected, Closing, Closed, Failure)를 계속 추적해야 하므로, 상태 관리가 중요

→ WebSocket의 특화된 통신 방식을 효율적으로 관리하기 위해 따로 구성하는 것이 좋다!

WebSocketHandler 구현 코드

class WebSocketHandler(private val serverUrl: String) {

  private val client = OkHttpClient()
  private lateinit var webSocket: WebSocket

  fun connect(onMessage: (String) -> Unit) {
    val request = Request.Builder().url(serverUrl).build()

    webSocket = client.newWebSocket(request, object : WebSocketListener() {

			// 연결이 성공적으로 열렸을 때 호출
      override fun onOpen(webSocket: WebSocket, response: Response) {
        super.onOpen(webSocket, response)
      }
			// 텍스트 메시지 수신
      override fun onMessage(webSocket: WebSocket, text: String) {
        super.onMessage(webSocket, text)
        onMessage(text)
      }
			// 바이너리 메시지를 수신
      override fun onMessage(webSocket: WebSocket, bytes: ByteString) {
        super.onMessage(webSocket, bytes)
      }
			// 서버가 연결을 닫으려 할 때 호출
      override fun onClosing(webSocket: WebSocket, code: Int, reason: String) {
        super.onClosing(webSocket, code, reason)
        // 클라이언트에서도 연결 정리
        webSocket.close(1000, null)
      }
			// 연결이 완전히 종료되었을 때 호출
      override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {
        super.onClosed(webSocket, code, reason)
      }
			// 연결 실패나 에러가 발생했을 때 호출
      override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
        super.onFailure(webSocket, t, response)
      }
    })
  }
  
	// 현재 연결된 웹소켓으로 메시지 전송
  fun sendMessage(message: String) {
    if (::webSocket.isInitialized) {
      webSocket.send(message)
      println("Sent message: $message")
    } else {
      println("WebSocket is not connected.")
    }
  }
	// 웹소켓 연결을 닫습니다. 정상적인 종료 코드(1000)와 함께 연결을 정리
  fun disconnect() {
    if (::webSocket.isInitialized) {
      webSocket.close(1000, "Client closed connection")
    }
  }
}

onClosing vs onClosed

onClosing

  • 서버 또는 클라이언트가 연결을 닫으려고 할 때 호출됩니다.
  • 연결 종료가 예정됨을 알리는 단계, 서버와 클라이언트 간에 종료 코드를 교환하는 시점
  • 리소스를 정리하거나 필요한 마지막 작업을 수행
  • 양쪽이 close() 호출을 완료해야 onClosed가 호출

onClosed

  • 연결이 완전히 종료되었을 때 호출
  • 서버와 클라이언트가 종료 절차를 마치고 연결이 깨끗하게 닫힌 상태
  • 연결 종료 이후의 작업을 수행
  • 더 이상 데이터를 주고받을 수 없음

ps. wss://echo.websocket.events 로 연결 테스트 해볼 수 있다!

0개의 댓글