티스토리 뷰

멀티코어에서 유의점 궁금하신분은 맨 아래쪽으로 가보세여^^~

그외 기타 유의점(밑에도 썼지만 걍 위에서만 보고싶을수도있으니깐)은

->버전을 확인하시라... 클라이언트랑 서버쪽 socket.io 버전이 호환이 안될수있음(https://socketio.github.io/socket.io-client-java/installation.html) <- 여기 들어가보세여 자바 socket.io 클라이언트 호환성이 나와있음

 

socket.io?

양방향 통신을 위해 웹 소켓 기술 활용하는 라이브러리

 

간략히 쓰는법을 적어보겠음(사실 이거만 알면됨)

socket.on('check_con',id_message)

-> 이렇게 on 한것에 {} 안에는 'check_con'이라는 이름의 이벤트가 일어났을때 어떤 일을 할지 적는것임

->id_message 이부분은 상대방이 나한테 보낸 데이터부분

socket.emit('msg_to_client',message)

->emit은 내가 상대방에게 'msg_to_client'라는 이름의 이벤트를 일어나도록 하는것, 이걸 하면 상대방은 socket.on('msg_to_client',message)이렇게 on으로 이벤트를 받게 됨, 

->message는 내가 상대방에게 보낼 데이터를 담는 부분

아래 예시의 시나리오

 

서버 코드(Node.js express)

var app = require("express")();
var http = require("http").createServer(app);
var io = require('socket.io')(http);

var port = 3000;

io.on('connection', function (socket) {//클라이언트 연결되면
  console.log(socket.id, 'Connected');//연결됨을 콘솔에 출력
  var id_message={
    id:`${socket.id} 나의 아이디`
  }
  socket.emit('check_con',id_message);
  
  socket.on('msg', function (data) {
      //클라이언트에게 msg가 emit되면 실행
    console.log(socket.id, data);
   
    console.log("-------------------");
    console.log('id: ',data.id);
    console.log('password: ',data.password);
    console.log("-------------------");
    var message={
      msg:`Server : "${data.id}" 당신의 id.`,
      msg2:"어떠세요?"
    }
    socket.emit('msg_to_client',message );//클라이언트로 메시지 전송
  });
  socket.on('disconnect',function(){//클라이언트 연결 끊어지면 자동 실행
      console.log('disconnected');
  })
});

http.listen(port, () => {//클라이언트 대기
    console.log("listening on *:" + port);
  });

-7번 줄: 어떤 클라이언트가 연결되면 io.on의 "connection" 이벤트 발생한다

-on은 이벤트 발생하면 수행할 일을 적는다, emit은 상대방에게 이벤트를 일어나도록 만듦

-9~12번 줄: json으로 안드로이드에게 보낼 데이터 id_message를 만든다

-socket.emit을 하면 해당 클라이언트에게만 전달되고 io.emit을 하면 지금 서버에 연결된 모든 클라이언트에게 이벤트 발생된다


안드로이드 코드

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.soke_test">
    <uses-permission android:name="android.permission.INTERNET" />
    <application
        android:usesCleartextTraffic="true"
       ...(생략)

-> 인터넷 권한을 주고 http를 사용하기 때문에 useCleartextTraffic으로 http사용을 허용한다

 

app레벨 build.gradle

dependencies {
    implementation ('io.socket:socket.io-client:2.0.1') { // excluding org.json which is provided by Android
         exclude group: 'org.json', module: 'json' }
  ...(생략)
}

socket.io 사용을 위해 라이브러리 추가한다

이때!!!!!!!!!!!!!! 서버의 socket.io의 버전과 호환되나 확인이 필요함(리액트에서 socket.io쓰는사람들도 마찬가지임)

https://socketio.github.io/socket.io-client-java/installation.html ->여기 공식사이트에 들어가보자

 

가보면 이렇게 호환성 얘기를 써놨음 만약에 socket.io연결이 안된다 그러면 hoxy? 버전이 차이나서 안되나 이런걸 확인해보자!

 

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical">
    <Button
        android:id="@+id/btn_con"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="연결"/>
    <TextView
        android:id="@+id/tv_text_conn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="연결안됨"
        />
    <Button
        android:id="@+id/btn_send"
        android:text="보내기"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />
    <TextView
        android:id="@+id/tv_text_from_server"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="온 메시지없음"
        />
    <TextView
        android:id="@+id/tv_text_from_server2"
        android:text="none"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />
</LinearLayout>

→연결 버튼을 누르면 서버에 연결, 서버에서 클라이언트의 아이디를 돌려주고 바로 밑 텍스트뷰에 클라이언트 아이디를 출력,

→보내기 버튼을 누르면 안드로이드에서 임의로 지정한 id password를 서버로 보낸다 서버에서 다시 두개 메시지를 안드로이드에게 보내주면 버튼 밑 텍스트뷰 두개에 출력함

 

MainActivity.java

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import org.json.JSONObject;

import io.socket.client.IO;
import io.socket.client.Socket;
import io.socket.emitter.Emitter;

public class MainActivity extends AppCompatActivity {
    private Socket mSocket;

    Button btn_conn,btn_send;
    TextView tv_text_con,tv_text_from_server,tv_text_from_server2;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btn_conn=findViewById(R.id.btn_con);
        btn_send=findViewById(R.id.btn_send);
        tv_text_con=findViewById(R.id.tv_text_conn);//서버로부터 온 클라이언트 id출력
        tv_text_from_server=findViewById(R.id.tv_text_from_server);//서버로부터 온 msg출력
        tv_text_from_server2=findViewById(R.id.tv_text_from_server2);//서버로부터 온 msg2출력
        btn_conn.setOnClickListener(new View.OnClickListener(){//연결버튼 클릭
            public void onClick(View view) {
                connect();//연결함수
            }
        });
        btn_send.setOnClickListener(new View.OnClickListener() {//보내기버튼 클릭
            @Override
            public void onClick(View view) {
                send();//보내기함수
            }
        });
    }
    void connect(){
        try {
            mSocket = IO.socket("http://10.0.2.2:3000");//안드로이드 avd사용시 로컬 호스트는 이 주소사용
            mSocket.connect();//위 주소로 연결
            Log.d("SOCKET", "Connection success : " + mSocket.id());
            mSocket.on("check_con", new Emitter.Listener() {
									//서버가 'check_con'이벤트를 일으킨경우
                @Override
                public void call(Object... args) {//args에 서버가 보내온 json데이터 들어간다
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            try{
                                JSONObject data=(JSONObject) args[0];
                                tv_text_con.setText(data.getString("id"));//json에서 id라는 키의 값만 빼서 텍스트뷰에 출력
                            }catch (Exception e){
                                Toast.makeText(getApplicationContext(), e.getMessage(),
                                        Toast.LENGTH_LONG).show();
                                e.printStackTrace();
                            }
                        }
                    });
                }
            });
        } catch (Exception e) {
            tv_text_con.setText("안됨");
            Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_LONG)
                    .show();
            e.printStackTrace();
        }

    }
    void send(){
        if(mSocket!=null){//연결된경우에만 보내기 가능
            JSONObject data=new JSONObject();//서버에게 줄 데이터를 json으로 만든다
            try{
                data.put("id","test2525");//위에서 만든 json에 키와 값을 넣음
                data.put("password","testpass");
                mSocket.emit("msg",data);//서버에게 msg 이벤트 일어나게 함

                mSocket.on("msg_to_client", new Emitter.Listener() {
										//서버가 msg_to_client이벤트 일으키면 실행
                    @Override
                    public void call(Object... args) {//args에 서버가 보낸 데이터 들어감
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                try{
                                    JSONObject data=(JSONObject) args[0];
                                    tv_text_from_server.setText(data.getString("msg"));//서버가 보낸 json에서 msg라는 키의 값만 텍스트뷰에 출력
                                    tv_text_from_server2.setText(data.getString("msg2"));//서버가 보낸 json에서 msg2라는 키의 값만 텍스트뷰에 출력
                                }catch (Exception e){
                                    Toast.makeText(getApplicationContext(), e.getMessage(),
                                            Toast.LENGTH_LONG).show();
                                    e.printStackTrace();
                                }
                            }
                        });
                    }
                });
            }catch(Exception e) {
                Toast.makeText(getApplicationContext(), e.getMessage(), Toast
                        .LENGTH_LONG).show();
                e.printStackTrace();
            }
        }
    }
    protected void onDestroy(){//어플리케이션 종료시 실행
        super.onDestroy();
       // mSocket.emit("disconnect",null);
        mSocket.disconnect();//소켓을 닫는다
    }   
}

-안드로이드(다른 클라이언트도 마찬가지)도 emit, on으로 이벤트 처리함

-안드로이드 avd 에서 localhost를 쓰고싶으면 10.0.2.2를 사용한다

 

 

실행 확인

cmd 켜서 서버 실행하는법

-윈도우면 dir로 파일을 확인하고 cd로 디렉터리 이동한다(친절하죠?^^)

-node 파일이름.js 를 명령어로 치면 해당 js코드가 실행됨

 

  • 서버 실행중, 연결 안된 상태

  • 연결 버튼 클릭

  • 보내기 버튼 클릭

  • 앱 종료


멀티코어 서버에서 유의점!!!

Node.js 를 쓸때... 멀티코어로 설정을 하는 경우가 있잖아요 그때 socket.io 연결이 안될수있음 ㅠㅠ 안드로이드뿐이 아니라 다른 웹 클라이언트도 마찬가지다

연결이 되면 자동으로 connect 이벤트가 발생하고 그 밑의 일들이 일어나야 하는데 전혀 되지 않고 

웹 클라이언트의 경우 net::ERR_EMPTY_RESPONSE 이런 에러가 나오고 걍 연결이 안되는 경우가 있음

안드로이드의 경우 서버 연결이 반복되고 안드로이드 쪽에서 연결을 끊지 않았는데 자기맘대로 계속 연결 끊김이 일어나는경우가 있다

위처럼 서버쪽에서 연결되면 socket init! 이 출력되게 했을때 계속 연결을 한번만 했는데도 자기맘대로 연결이 끊겼다 연결됐다하는게 반복되고

mSocket.on("disconnect", new Emitter.Listener() {
                @Override
                public void call(Object... args) {
                    Log.d("log","ddddddddddddddddddddddd");
                }
            });

요렇게 안드로이드에서 연결 끊어졌을때 ddddd출력하게 했을때

이렇게 자동끊김이 계속 생김

자동으로 연결이 자꾸 끊어지니깐 서버랑 소켓 통신이 안됨

문제원인은 나도 사실 잘은 모르지만 원래 socket.io가 시작될때 http폴링 모드에서 시작되고 그담에 양쪽이 다 ok했을때 그다음부터 websocket연결이 된다 근데 다중 코어를 쓰면 고정되지 않은 로드밸런서 있는 경우에 폴링 요청에 문제가 있을수 있다고함 그래서 websocket모드로만 연결하도록 해야된다는듯???? 

영어 잘하시는분들은 여기로-> https://stackoverflow.com/questions/42478997/socket-io-client-getting-connected-disconnected-repeatedly 

 

socket.io client getting connected disconnected repeatedly

In case of multiple socket.io servers (ALB balanced) client is getting connected and disconnected from both the nodes giving 'transport error'. Ideally it should be connected to one node and remain

stackoverflow.com

 

암튼 그래서 해결방법은 뭐냐? 아주 간단..

https://socketio.github.io/socket.io-client-java/initialization.html#IO_factory_options

 

socket.io-client – Initialization

Initialization Table of content Creation of a Socket instance URI uri = URI.create("https://example.com"); IO.Options options = IO.Options.builder() // ... .build(); Socket socket = IO.socket(uri, options); Unlike the JS client (which can infer it from the

socketio.github.io

여기 들어가서 Low-level engine options 부분을 보면

이런식으로 웹소켓 옵션을 정해주는 옵션 설정방법을 알려줌

WebSocket.NAME에 "websocket" 을 적으면됨

 

io.socket:socket.io-client:1.0.1'

난 지금 이 버전을 쓰고있으니 1.0.1 버전일때 하려면 아래처럼 한다

private Socket mSocket;//소켓통신을 위한 소켓 객체
private URI uri= URI.create("서버주소");
private IO.Options options;

protected void onCreate(Bundle savedInstanceState) {

	options=new IO.Options();
    options.transports=new String[]{"websocket"};//웹소켓 옵션 설정
    mSocket=IO.socket(uri,options);
    mSocket.connect();

}

Hoxy..? null exception(소켓 연결 해지시 강제종료) 에러 나오나요?.......

disconnect 이벤트 emit과 socket.disconnect()를 둘다 사용하진 않았는가 확인해보십쇼

https://demat.tistory.com/31  <- 자세한건 여기루....(별로자세하진않지만....이거보단자세함..)

 

 

 

-참고 url

-socket.io java client 공식사이트:https://socketio.github.io/socket.io-client-java/installation.html

-socket.io설명: [Node.js] socket.io로 실시간 채팅 구현하기 (1) (tistory.com)

-socket.io설명:https://www.peterkimzz.com/websocket-vs-socket-io/

-socket.io서버예시: Node.js 서버에서 Socket.IO로 실시간 통신하기 - 기초 - 메모장 (fred16157.github.io)

-socket.io서버예시(많은도움됨):https://jsikim1.tistory.com/165

-안드로이드 코틀린예시:https://angangmoddi.tistory.com/222

-안드로이드 java예시 (많은도움됨): https://m.blog.naver.com/mym0404/221344144643

-안드로이드 avd 로컬호스트 접속: https://new93helloworld.tistory.com/382

-안드로이드 avd, 실제 디바이스 로컬호스트접속: https://uareuni.tistory.com/30

-안드로이드 java예시 (도움 많이됨): https://velog.io/@dongchyeon/안드로이드-socket.io를-이용한-간단한-채팅-어플-만들어보기-1-초기-세팅

-안드로이드 java예시 (도움 많이됨): https://mainia.tistory.com/5720

-js에서 json다루기: https://java119.tistory.com/54

-socket.io 함수들:https://www.zerocho.com/category/NodeJS/post/57edfcf481d46f0015d3f0cd

-socket.io함수들:https://inpa.tistory.com/entry/SOCKET-📚-SocketIO-사용-해보기

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/10   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
글 보관함