Netty(네티)

Netty 소켓 서버에 안드로이드 접속해서 채팅하기 Netty Socket Server and Android

알통몬_ 2017. 12. 15. 10:53
반응형


공감 및 댓글은 포스팅 하는데

 아주아주 큰 힘이 됩니다!!

포스팅 내용이 찾아주신 분들께 

도움이 되길 바라며

더 깔끔하고 좋은 포스팅을 

만들어 나가겠습니다^^

 


Netty socket Server and android client socket communication


지난 포스팅까지해서

네티 채팅 서버/클라이언트를 만들어서, 이크립스 콘솔에서 채팅하는 기능을 만들어보았는데요.


클라이언트를 안드로이드 쪽으로 와서 같은 기능으로 구현해보았습니다.

서버는

2017/12/13 - [Netty(네티)] - Netty(네티) 채팅 서버/클라이언트 [1] : 채팅 서버 만들기

여기서 조금 수정되었습니다.

ChatServerInitializer.java 파일이 수정되었는데요.

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
32
33
34
35
36
37
38
39
40
41
42
import java.util.List;
 
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.Delimiters;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.ssl.SslContext;
 
public class ChatServerInitializer extends ChannelInitializer<SocketChannel> {
 
    private final SslContext sslCtx;
    
    public ChatServerInitializer(SslContext sslCtx) {
        this.sslCtx = sslCtx;
    }
    
    @Override
    protected void initChannel(SocketChannel arg0) throws Exception {
        ChannelPipeline pipeline = arg0.pipeline();
        
        //pipeline.addLast(sslCtx.newHandler(arg0.alloc()));
        //pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
        pipeline.addLast(new ByteToMessageDecoder() {
            @Override
            public void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> outthrows Exception {
                out.add(in.readBytes(in.readableBytes()));
            }
        });
        pipeline.addLast(new StringDecoder());
        pipeline.addLast(new StringEncoder());
        
        pipeline.addLast(new ChatServerHandler());
 
    }
 
}
cs

//pipeline.addLast(new DelimiterBasedFrameDecoder(...); 을 주석처리하고,

pileline.addLast(new ByteToMessageDecoder() {

@Override

public void decode(...) {


}

}); 로 대체하였습니다.

기존 코드를 사용하게 되면 안드로이드에서 보내는 메시지를 서버에서 

언제 출력해 줄지를 알 수가 없어서 정상적으로 동작을 하지 않습니다.

다음은 안드로이드 코드입니다.

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
public class MainActivity extends AppCompatActivity {
 
    Handler handler;
    String data;
    SocketChannel socketChannel;
    private static final String HOST = "접속할 네티서버 IP";
    private static final int PORT = 5001;
    String msg;
    ActivityMainBinding binding;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        handler = new Handler();
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    socketChannel = SocketChannel.open();
                    socketChannel.configureBlocking(true);
                    socketChannel.connect(new InetSocketAddress(HOST, PORT));
                } catch (Exception ioe) {
                    Log.d("asd", ioe.getMessage() + "a");
                    ioe.printStackTrace();
 
                }
                checkUpdate.start();
            }
        }).start();
 
        binding.sendMsgBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    final String return_msg = binding.sendMsgEditText.getText().toString();
                    if (!TextUtils.isEmpty(return_msg)) {
                        new SendmsgTask().execute(return_msg);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
 
    private class SendmsgTask extends AsyncTask<String, Void, Void> {
        @Override
        protected Void doInBackground(String... strings) {
            try {
                socketChannel
                        .socket()
                        .getOutputStream()
                        .write(strings[0].getBytes("EUC-KR")); // 서버로
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    binding.sendMsgEditText.setText("");
                }
            });
        }
    }
 
    void receive() {
        while (true) {
            try {
                ByteBuffer byteBuffer = ByteBuffer.allocate(256);
                //서버가 비정상적으로 종료했을 경우 IOException 발생
                int readByteCount = socketChannel.read(byteBuffer); //데이터받기
                Log.d("readByteCount", readByteCount + "");
                //서버가 정상적으로 Socket의 close()를 호출했을 경우
                if (readByteCount == -1) {
                    throw new IOException();
                }
 
                byteBuffer.flip(); // 문자열로 변환
                Charset charset = Charset.forName("EUC-KR");
                data = charset.decode(byteBuffer).toString();
                Log.d("receive""msg :" + data);
                handler.post(showUpdate);
            } catch (IOException e) {
                Log.d("getMsg", e.getMessage() + "");
                try {
                    socketChannel.close();
                    break;
                } catch (IOException ee) {
                    ee.printStackTrace();
                }
            }
        }
    }
 
    private Thread checkUpdate = new Thread() {
 
        public void run() {
            try {
                String line;
                receive();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    };
 
    private Runnable showUpdate = new Runnable() {
 
        public void run() {
            String receive = "Coming word : " + data;
            binding.receiveMsgTv.setText(receive);
        }
 
    };
 
    @Override
    protected void onDestroy() {
        super.onDestroy();
        try {
            socketChannel.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
cs


두 대의 에뮬레이터를 실행시키고 해보시면 정상 동작할 거에요 ^^

layout은 각 자 편하신 대로 만드시면 됩니닷 ^^

이상입니다.

감사합니다.


반응형