210202

안드로이드에서 Stomp 라이브러리를 활용하여 서버와 소켓통신하기 본문

Android/OP.GG 프로젝트

안드로이드에서 Stomp 라이브러리를 활용하여 서버와 소켓통신하기

dev210202 2021. 9. 13. 15:15

이번 프로젝트에서 소켓통신을 Stomp로 구현해보면서 안드로이드에서 Stomp 라이브러리를 사용하는 방식에 대한 자료들이 초보자가 구현하기엔 설명이 부족한 것들이 많아서 초보자도 쉽게 구현할 수 있는 Stomp를 활용한 소켓통신 구현방법에 대해 포스팅 해본다.

 

Stomp란?

웹소켓 위에서 동작하는 프로토콜

 

왜 Stomp를 사용했을까?

보통 소켓통신을 구현할 때 socket.io를 많이 사용한다. 

socket.io는 웹소켓을 기반으로 이를 활용한 라이브러리라 같은 기능을 구현하더라도 약간 느린대신, 많은 편의성을 제공한다.

웹소켓 방식은 데이터 전송이 많은 경우 빠르고 비용이 적은 작업에 유리하고 socket.io는 서버에서 연결된 소켓들을 세밀하게 관리해야하는 경우 유지보수 측면에서 유리하다.

따라서 우리 프로젝트에서는 채팅 데이터 및 지도 데이터 등 데이터 전송이 꽤 있는편이고, 연결된 소켓들을 관리해야 할 필요성이 적으므로 웹소켓 방식을 선택하여 Stomp를 사용한 것 같다. 

 

Android에서 Stomp 사용방법

안드로이드에서 Stomp를 구현하려면 라이브러리를 사용해서 구현해야하는데 공식적으로 제공되는 라이브러리는 없고 개발자들이 스스로 만든 라이브러리를 이용해야한다. 대표적인 라이브러리는 아래 링크가 있다.

https://github.com/NaikSoftware/StompProtocolAndroid

 

Android에서 Stomp를 사용하여 소켓통신 구현

build.gradle, setting.gradle 설정

 

Stomp를 활용하기 위해 라이브러리를 gradle에 추가한다.

먼저 build.gradle(Module: )에서 다음과 같이 추가해준다.

dependencies {

    // stomp
    implementation 'com.github.NaikSoftware:StompProtocolAndroid:1.6.6'

    //rx
    implementation 'io.reactivex.rxjava2:rxjava:2.2.5'
    implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'

}

StompProtocolAndroid 라이브러리에서 Rx를 기반으로 소켓통신을 하기때문에 Rx도 추가해줘야한다.

 

그 다음 build.gradle(Project: )에서 다음과 같이 추가해준다.

repositories { 
    jcenter()
    maven { url "https://jitpack.io" }
}

위의 두가지를 했는데 오류가 난다면 setting.gradle에도 다음과 같이 추가해야 한다(Android Arctic Fox 버전 이상에서는 위치가 변경되어서 setting.gradle에도 해줘야한다)

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
        jcenter()
        maven { url "https://jitpack.io" }
    }
}

 

그 다음 Stomp를 구현한다.

class MainViewModel : ViewModel() {


    // val url = "http://example.com:8080/"
    val url = "ws://example.com:8080/socket/websocket" // 소켓에 연결하는 엔드포인트가 /socket일때 다음과 같음
    val stompClient =  Stomp.over(Stomp.ConnectionProvider.OKHTTP, url)
    
    fun runStomp(){
    
    	stompClient.topic("/topic/message/test0912").subscribe { topicMessage ->
            Log.i("message Recieve", topicMessage.payload)
        }
       
        val headerList = arrayListOf<StompHeader>()
        headerList.add(StompHeader("inviteCode","test0912"))
        headerList.add(StompHeader("username", text.value))
        headerList.add(StompHeader("positionType", "1"))
        stompClient.connect(headerList)

        stompClient.lifecycle().subscribe { lifecycleEvent ->
            when (lifecycleEvent.type) {
                LifecycleEvent.Type.OPENED -> {
                    Log.i("OPEND", "!!")
                }
                LifecycleEvent.Type.CLOSED -> {
                    Log.i("CLOSED", "!!")

                }
                LifecycleEvent.Type.ERROR -> {
                    Log.i("ERROR", "!!")
                    Log.e("CONNECT ERROR", lifecycleEvent.exception.toString())
                }
                else ->{
                    Log.i("ELSE", lifecycleEvent.message)
                }
            }
        }

        val data = JSONObject()
        data.put("userKey", text.value)
        data.put("positionType", "1")
        data.put("content", "test")
        data.put("messageType", "CHAT")
        data.put("destRoomCode", "test0912")

        stompClient.send("/stream/chat/send", data.toString()).subscribe()
    }
}

url을 설정할때 연결하려는 주소가 http라면 ws, https라면 wss로 바꿔야한다. 또한 마지막에 /websocket을 꼭 붙여야한다.

 

그 다음 메시지를 받기위한 구독을 설정한다. 

stompClient.topic("subscribe할 주소").subscribe { topicMessage ->

이 부분에서 밑줄친 subscribe할 주소부분에 서버에서 제공하는 구독에 해당하는 값을 넣어주면 된다.

 

헤더를 넣고싶으면 다음과같이 connect할때 설정한 헤더들을 넣어주면 된다.

val headerList = arrayListOf<StompHeader>()
headerList.add(StompHeader("inviteCode","test0912"))
headerList.add(StompHeader("username", text.value))
headerList.add(StompHeader("positionType", "1"))
stompClient.connect(headerList)

그 다음 코드는 stompClient의 lifeCycle의 변경에 따라 로그를 찍는 코드이다.

stompClient.lifecycle().subscribe { lifecycleEvent ->
            when (lifecycleEvent.type) {
                LifecycleEvent.Type.OPENED -> {
                    Log.i("OPEND", "!!")
                }
                LifecycleEvent.Type.CLOSED -> {
                    Log.i("CLOSED", "!!")

                }
                LifecycleEvent.Type.ERROR -> {
                    Log.i("ERROR", "!!")
                    Log.e("CONNECT ERROR", lifecycleEvent.exception.toString())
                }
                else ->{
                    Log.i("ELSE", lifecycleEvent.message)
                }
            }
        }

채팅을 보낼때는 보낼 채팅메시지의 값에 맞춰서 보낼 주소에 보내주면 된다.

val data = JSONObject()
data.put("userKey", text.value)
data.put("positionType", "1")
data.put("content", "test")
data.put("messageType", "CHAT")
data.put("destRoomCode", "test0912")
stompClient.send("/stream/chat/send", data.toString()).subscribe()

 

구현하면서 느낀점

확실히 socket.io보다는 불편한점이 많다. 일단 참고할 자료의 양이 너무나도 적고 안드로이드에서 Stomp를 지원해주는 라이브러리도 개인 개발자의 라이브러리를 사용해야하고 라이브러리에 대한 설명도 자세하지않다.

 

소켓통신을 구현할때는 socket.io를 사용하는게 가장 쉽고 빠르게 개발할 수 있는 방식인것 같다.

 

혹시라도 이 글을 보신 서버개발자분이 있다면 소켓통신은 꼭 socket.io를 사용할 수 있게 서버를 만들어주시면 좋겠다. 

Comments