일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 서비스 디스커버리
- Gradle
- Spring Cloud Config
- BFS
- 구간 트리
- 주울
- 달팽이
- 도커
- 스택
- docker-compose
- ZuulFilter
- Zuul
- Logback
- dp
- 메모이제이션
- 스프링 시큐리티
- 트리
- 비트마스킹
- 이분 매칭
- 게이트웨이
- Java
- 플로이드 와샬
- 이분 탐색
- spring cloud
- 유레카
- 백트래킹
- spring boot
- 다익스트라
- 완전 탐색
- 구현
- Today
- Total
Hello, Freakin world!
[채팅앱][클라이언트] 논블락킹 ConnectionLoop 기능 구현 및 고찰 본문
ConnectionLoop 는 서버와의 연결에 실패했을 때의 상황을 처리하기 위해 구현했다.
사용자의 커맨드에 따라 다시 연결을 시도할지, 연결을 그만두고 애플리케이션을 종료할지 선택할 수 있다.
코드
private void connectionLoop() {
while(true) {
System.out.println("연결 중...");
Optional<SocketChannel> socketChannelOpt = Optional.ofNullable(channelManager.connect());
if(socketChannelOpt.isPresent()){
boolean isConnected = channelManager.finishConnect(socketChannelOpt.get());
if(isConnected) {
System.out.println("연결 성공.");
break;
}
}
failureAction();
}
}//connectionLoop
private void failureAction() {
System.out.println("연결 실패.다시 연결하시겠습니까? [y/n]");
Scanner scanner = new Scanner(System.in);
String command = scanner.nextLine();
if(command.equals("n")) {
System.out.println("애플리케이션이 종료됩니다.");
System.exit(0);
}
if(command.equals("y")) {
System.out.println("다시 연결합니다.");
}
}
구현하면서 발생했던 문제들에 대한 고찰
참고로 구현하는데 시간이 정말 많이 걸렸다...
난관에 부딪혔던 부분은 대부분 스레드를 다루면서 발생하는 문제였는데,
1. 스레드에 대한 이해 부족
논블락킹 모드로 구현했기 때문에 connect 메서드는 현재 상태에 따라 바로 연결에 성공되었는지, 실패했는지를 반환한다. 이는 싱글스레드라면 문제가 없다(위 코드는 싱글 스레드에서 작동한다).
내가 이전에 생각했던 아키텍처는 모든 이벤트를 register 메서드를 이용해 selector 객체 등록하고
EventLoop 스레드에 작업을 위임했다. 그래서 connect가 성공했는지를 이벤트를 발생시킨 다음 시점에 검사하면
상황에 따라 검사가 제대로된 결과를 내지 못할 때가 발생했다.(이를 알아차리는데도 엄청나게 오래 걸렸다.)
이 문제에서 얻은 결론은 논블락킹 프로세스에서 이벤트 작업이 다른 스레드에서 이뤄질 때, 불편한 경우가 생기는데
그 경우는 메인 스레드에서 그 결과를 추적할 때이다.
read와 write는 이와는 다르다.
write와 관련된 대부분의 프로세스의 주된 관심사는 보낼 데이터를 어떻게 가공하는지다. 가공한 데이터를 마지막에 write를 이용해 보내면 그걸로 끝이다.
read 역시 마찬가지다. 데이터를 읽고 어떻게 데이터를 가공할지가 주된 관심사다.
다시 말해, 데이터를 일방적으로 보내거나 받는 경우는 작업을 비동기로 처리해도 ok다.
하지만 connect 프로세스와 같이 현재 스레드에 상태 정보를 가지고 있고, 이 상태의 변화를 체크해야하는 경우는 싱글스레드가 훨씬 편하다는 것이다. 어떻게 Future를 이용해 구현할 수도 있을 것 같긴하지만 이는 나중에 알아보도록 하자.
2. api에 대한 이해 부족
이 부분도 아주 큰 작용을 했다.
모르는 api에 대해서 대부분의 경우 예제를 통해 간단하게 테스트해보고 사용하는 식으로 학습하곤 했다.
하지만 복잡도가 꽤 있는, 자신만의 애플리케이션을 만들려면 깊은 이해가 필요했고
공식 api 문서를 꼼 꼼 히 읽는게 정말 큰 도움이 됐다.
앞으로 공식 문서를 번역해 블로그에 정리하는 일도 거리낌이 없어야겠다.
나심 탈레브의 '안티프래질'에서 "이해하려면 적게 알아도 되지만, 그걸 쓰려면(write)하려면 마스터해야한다."
라는 문구가 생각났다. (정확한지는 모르겠지만 저런 뉘앙스였다.)
'Toy Project > 채팅 앱 만들기' 카테고리의 다른 글
[채팅앱] ChatRoom 서버가 제공할 API (0) | 2020.03.20 |
---|---|
[채팅앱] 또 한번의 코드 뒤엎기 (0) | 2020.03.16 |
[채팅앱] 클라이언트 서버 통신 - 첫번째 목표 설정 (0) | 2020.03.02 |
[채팅앱][클라이언트] EventHandler 코드 작성하기 (0) | 2020.03.01 |
[채팅앱][클라이언트] EventHandler 클래스 및 아키텍처 수정 (0) | 2020.02.28 |