마스터Q&A 안드로이드는 안드로이드 개발자들의 질문과 답변을 위한 지식 커뮤니티 사이트입니다. 안드로이드펍에서 운영하고 있습니다. [사용법, 운영진]

Android 소켓 연동 이 안되는 이유

0 추천

안녕하세요 소켓연동을 구현을 했는

 try {
            mSocket = IO.socket("http://10.0.2.2:3000")

            mSocket.connect()
            mSocket.emit("setting", token)
            Log.d(TAG, "onCreate: 소켓연결 성공")
            //서버에 신호 보내는거같음 밑에 에밋 리스너들 실행
            //socket.on은 수신
            mSocket.on("sendMessage", sendMessage)


            val json = JSONObject()
            json.put("token", token)
            mSocket.emit("connects  ", json)
            val userId = JSONObject()
            userId.put("token", token)
            userId.put("roomId", args.groupId)
            //socket.emit은 메세지 전송임
            mSocket.emit("join", userId)
        } catch (e: JSONException) {
            Log.d(TAG, "onCreate:  에러 ${e}")
            e.printStackTrace()
        }

        hasConnection = true

        chat_Send_Button.setOnClickListener {
            //아이템 추가 부분
            sendMessage()

        }
    }


    private fun getToken() {
        signViewModel.readToken.asLiveData().observe(this) {
            token = it.token
        }
    }

    private fun setAdapter() {
        binding.studyMeetingRecyclerView.apply {
            adapter = mAdapter
            showVertical(context)
        }
    }


    private var sendMessage: Emitter.Listener = Emitter.Listener { args ->
        runOnUiThread {
            Log.e("socket", "sendMessage return : $${args[0]}")
            val data = args[0] as JSONObject
            val name: String
            val message: String
            val profile_image: String
            try {
                Log.e("socket", "sendMessage return : $data")
                name = data.getString("name")
                message = data.getString("message")
                profile_image = data.getString("profileImg")

                val format = ChatModel(name, message, profile_image, "null")
                mAdapter.addItem(format)
                mAdapter.notifyDataSetChanged()
                Log.e("new me", name)
            } catch (e: Exception) {
                Log.d(TAG, "onNewMessage: 에러 ${e} ")
                return@runOnUiThread
            }
        }
    }


    // send button 을 누르면 server 에 있는 sendMessage 가 호출된다.
    private fun sendMessage() {


        val message = binding.messageEdit.text.toString().trim { it <= ' ' }
        if (TextUtils.isEmpty(message)) {
            return
        }
        binding.messageEdit.setText("")
        val jsonObject = JSONObject()
        try {
            Log.d(
                TAG,
                "sendMessage: message  ${message} groupId : ${args.groupId} token : ${token}"
            )
            jsonObject.put("token", token)
            jsonObject.put("roomId", args.groupId)
            jsonObject.put("message", message)
            mSocket.emit("sendMessage", jsonObject)

        } catch (e: JSONException) {
            Log.d(TAG, "sendMessage: 에러 ${e}")
            e.printStackTrace()
        }
        Log.d("socket", "sendMessage : object $jsonObject")


    }

    override fun onDestroy() {
        super.onDestroy()
        mSocket.disconnect()
    }

데 서버에 로그를 찍어봐도 데이터가 안넘어가고 연동이 안되는 것 같습니다.

에러도 안뜨고 뭐가 문제인지 모르겠어요 ㅠㅠ

hifl (670 포인트) 님이 2021년 11월 23일 질문
Socekt.IO를 사용하시고 계시는 것 같은데, 서버도 Socket.IO를 이용해서 구축하셨나요?
네 socket.io 와 nest 웹소켓으로 구축했습니다.
서버주소가 로컬 애뮬레이터 주소처럼 보이네요. 애뮬레이터의 경우는 API 27 전후로 해서 ClearText세팅을 해주어야 하는 걸로 알고 있습니다. 자세한 내용은 개발자 페이지를 확인해 보시죠.
https://developer.android.com/training/articles/security-config
android:usesCleartextTraffic="true" 으로 했는데도 안되네요
알려드린 링크처럼 securty-config도 세팅하셨나요?
<?xml version="1.0" encoding="utf-8"?>
    <network-security-config>
        <domain-config cleartextTrafficPermitted="false">
            <domain includeSubdomains="true">secure.example.com</domain>
        </domain-config>
    </network-security-config>
    
이렇게 세팅할려고 했더니 java.net.UnknownServiceException: CLEARTEXT communication to 10.0.2.2 not permitted by network security policy 이런 오류가 떠 세팅을 못했습니다.
10.0.2.2 와 연결을 하셔야 하므로  10.0.2.2 를 추가하셔야 하지 않을까요?
<?xml version="1.0" encoding="utf-8"?>
    <network-security-config>
        <domain-config cleartextTrafficPermitted="true">
            <domain includeSubdomains="true">10.0.2.2</domain>
        </domain-config>
    </network-security-config>
그렇네요
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config cleartextTrafficPermitted="true">
        <domain includeSubdomains="true">10.0.2.2</domain>
    </domain-config>
</network-security-config>
로 했더니 됩니다. 하지만 소켓 연동에는 아직도 연결이 안되는 것 같네요
혹시 브라우저나 telenet, postman 등으로는 서버에 접속이 되나요? 그리고 서버가 돌아가는 머신의 IP주소로도 접속을 시도해 보세요. 사설 IP가 존재할 겁니다.
서버에 접속이 되는건 확인했습니다. 하지만 소켓연동할때는 서버에 접속이 안되는 것 같으면 무언가 로직상의 문제라고 생각해봐야겟죠?
일단은 로그캣에서 관련 로그가 있는지 잘 체크해 보세요. 그리고 혹 internet 퍼미션 문제는 아니겠죠?
네 인터넷 퍼미션은 다 추가해줬습니다.
그리고   mSocket.connect()
            Log.d(TAG, "onCreate: 소켓연결 성공 ${mSocket.connected()}")
이렇게 로그를 찍어봤더니 mSocket.connected 부분이 false로 나오네요 그러면 연동이 실패한거겟죠?
글쎄요. catch 하신 에러는 아래처럼 JSONException 인데, 커넥션 에러라면 capture가 되지 않았을 것 같은데요.
} catch (e: JSONException) {
           Log.d(TAG, "onCreate:  에러 ${e}")
           e.printStackTrace()
 }
혹시 연결은 되었는데, JSON을 처리할 때 에러간 난 게 아닐까요?

죄송, 제가 글을 좀 잘못 읽어나 보네요.
그 부분에 log가 안찍히는걸 보니 에러난 건아닌것 같습니다..
이런 종류의 문제는 직접 디버그를 해보지 않으면 문제를 찾는 게 쉽지 않은 것 같네요. 혹  Github에 샘플 앱은 확인해 보셨나요?
https://github.com/socketio/socket.io-client-java
https://github.com/nkzawa/socket.io-android-chat
Socket.IO에서 커넥션 여부를 확인하는 방법 중의 하나가, 아랫처럼 콜백을 사용하면 되는 것 같네요.
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mSocket.on(Socket.EVENT_CONNECT_ERROR, onConnectError);
    mSocket.on(Socket.EVENT_CONNECT_TIMEOUT, onConnectError);
    mSocket.connect();
}


private Emitter.Listener onConnectError = new Emitter.Listener() {
    @Override
    public void call(Object... args) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(getApplicationContext(), "Unable to connect to NodeJS server", Toast.LENGTH_LONG).show();
            }
        });
    }
};


@Override
protected void onDestroy() {
    super.onDestroy();

    mSocket.disconnect();
    mSocket.off(Socket.EVENT_CONNECT_ERROR, onConnectError);
    mSocket.off(Socket.EVENT_CONNECT_TIMEOUT, onConnectError);
}

@Override
protected void onDestroy() {
    super.onDestroy();

    mSocket.disconnect();
    mSocket.off(Socket.EVENT_CONNECT_ERROR, onConnectError);
    mSocket.off(Socket.EVENT_CONNECT_TIMEOUT, onConnectError);
}

그리고 mSocket.connect() 다음의 접속 후 최초의 메세지를 전송하는 부분은 비동기로 처리하셔야 하는게 아닌지 모르겠네요.
한번 시도해 보도록 하겠습니다 !
Unable to connect to NodeJS server" 이 뜨는걸 보니 서버와 제대로 연결이 안되어 있엇던것 같네요.
스택오버플로우 원본 링크도 참조하세요. 거기에 질문 올리신 분이 본인 서버와 안드로이드 코드 링크를 걸어 놓으셨네요. https://stackoverflow.com/questions/34483159/socketio-android-not-emitting-connection-event
비교해 보시면 더 도움이 되실 것 같아요.
그래도 안되는 것 같네요 ㅠㅠ
발생하는 에러가 io.socket.engineio.client.EngineIOException: xhr poll error 인데,
Github에 다른 분들이 이슈를 올린 적이 있네요.
https://github.com/socketio/socket.io-client-java/issues/56
티켓은 클로즈되었지만, 실제로 완전하게 동작하는 솔루션은 없는 듯 합니다. 애뮬레이터에서 localhost에 접근하는 경우에는 테스트가 원활하지 않네요. 혹시 디바이스가 있으시면 디바이스를 통해 테스트를 해보시죠?

답변 달기

· 글에 소스 코드 보기 좋게 넣는 법
· 질문에 대해 추가적인 질문이나 의견이 있으면 답변이 아니라 댓글로 달아주시기 바랍니다.
표시할 이름 (옵션):
개인정보: 당신의 이메일은 이 알림을 보내는데만 사용됩니다.
스팸 차단 검사:
스팸 검사를 다시 받지 않으려면 로그인하거나 혹은 가입 하세요.
...