-
websocket:채팅JAVA 2021. 7. 27. 17:16
websocket + 네트워크운영 이해
데이터 보낼 때 송수신 측에서 받는 방식
1) TCP/IP
수신측이 보내는 데이터는 패킷단위로 전송되어 송신측이 받는다.
핸드쉐이크 : 서로 데이터 유실이 없는지 확인하여 계속 소통하며 확인한다.
- 장점 : 안전하다.
- 단점 : 느리다.
2) UDP
핸드쉐이크가 없다.
- 장점 : 빠르다 (TV 같은 것, 빠르다)
- 단점 : 데이터가 몇몇 유실될 수 있다.(가끔 끊기는 이유)
* TCP/IP 기반의 프로토콜 종류 (1) http
: TCP 기반에서 더 추가하여 http 라는 규약이 생긴 것.(2) smtp (3) FTP (4) 사용자가 직접 TCP/IP 기반의 프로토콜을 만들 수도 있다.
* 네트워크 운영 개념 client - server 소통 중 server
1) 서버 socket 준비
2) bind(80) : port 가 80 으로 시작하는 얘로 연결걸 때 본인이 나오겠다고 설정함
(톰캣이면 bind 가 8080)
3) listen (항상 대기)
4) accept ( client 가 연결을 바랄 때 응답 )
5) receive : 클라이언트 socket 을 전달받음client :
1) 클라이언트 socket 준비
2) connect :서버에 연결을 시도:연결을 걸기만 할 뿐 받아들이는 건 못함
3) send : 서버가 accept 한 후 서버에 클라이언트 socket 을 전달
4) close : 통신끝나고 클라이언트가 통화 끝냄 ( 서버에 끝냈다고 전달 하는 것 )socket?
의사소통을 주고받는 도구(전화기같은 느낌)
client 가 connect 걸어서 socket 으로 소통을 시도 -> acept 하여 server 에 있는 socket 이 반응* 네트워크 운영 중 서버 안의 클라이언트 끼리 소통할 수 있는 방법 ( = 이게 채팅 )
같은 서버안이라도 서버와 클라이언트의 대화지 클라이언트끼리는 서로를 인식할 수가 없다.
아래에 예제 참고!1번 방법 : 메세지를 보내는 클라이언트를 server 로 만들어 준다.
( 직접 server 로 만들어 위의 '네트워크 운영 개념' 대로 server가 하는 작업을 만들어줘야 한다.
하지만 아래 spring에서 실습에서 사용한 라이브러리가 저 과정을 자동으로 해줌 )javascript 에서 작업
1) new WebSocket : 기본적으로 js 에 있는 객체 ( 그래서 브라우저도 알고 있다. )
이를 통해 클라이언트의 소켓들을 받아서 서로에게 마치 전달되는 것처럼(server처럼)만들어 줌spring 에서 작업 ( 현재 서버는 spring 운영으로 가는 중 )
1) 'spring-websocket' library 의존성에 다운 ('2)' 의 클래스가 있는 라이브러리.)
+ 'jackson-databind' library ( ajax 통신할 때 다운받는것 // 이미 받았다. //없다면 아래 참고하여 다운! )
2) TextWebSocketHandler : 이 클래스를 상속받아 handleTextMessage() 메서드를 override 해준다.
= 메세지 처리기 ( 클라이언트에서 온 메시지 처리 )
3) WebSocketConfigurer: 이 인터페이스를 구현하여 registerWebSocketHandlers() 메서드를 override 하여 '2)' 설정한 클래스를 add
= 메세지 처리기 등록 ( spring 이 javascript 의 WebSocket 에 대응하여 응답하라고 알려주기 위해 등록 )
( 마치 resource 가 오면 WebMvcConfigurer를 상속받은 클래스로 addResourceHandlers() 메서드를 override 해서
해당 요청명과 폴더를 add 했듯, 과정이 똑같다.)
WebSocket 개요
http 프로토콜이 아닌 ws 프로토콜로 두개의 프로토콜을 한 서버에서 다루는 건 힘들다. (서버 하나 = 프로젝트 하나)
채팅 전용 서버 만드는게 프로젝트 하나를 따로 만드는것과 같은 의미이다.
요청명만 설정해놓으면 다른 프로젝트에서 아래 예제의 프로토콜을 사용하여 (어차피 같은 ip:port 인 host 이다) 연결이 가능하다.
1. 의존성 다운
: spring-websocket 의 version 은 spring-webmvc API 와 똑같은 버전으로
<!-- json --> // 있다면 다운 안받아도 됨 <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.10.1</version> </dependency> <!-- spring-websocket --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-websocket</artifactId> <version>5.0.2.RELEASE</version> </dependency>
1) jackson-databind
이는 Spring 과 관련이 있는 것은 아니고 java 와 js 가 JSON 객체를 주고 받게 하는
@ResponseBody, @RequestBody 를 쓰려는 의미이기 때문에
spring 이 아니더라도 이걸 낀다. (다른 라이브러리도 존재하지만 해당 라이브러리가 가장 괜찮다.)2) spring-websocket
이는 Spring 과 관련이 있으며 spring 에서 websocket 을 쓸 수 있게 하는 것이다.
해당 라이브러리가 JSON 객체를 주고 받기 때문에 ( js 의 websocket 을 받아야 한다 ) 위의 라이브러리가 필요한 것이다.
이 라이브러리가 jsp-spring 운영체제에서 내가 직접 했어야 할 위의 '네트워크 운영 개념' 의 server 내용을 알아서 작업해준다.
client 내용만 설정하면 된다.(jsp안 javascript 가 client 단. java는 중재자하는 중인 실제 server 단)
client 내용 중 close() 만 client창에서(jsp) 안해도 되고 server단에서 하면 된다.
( jdbc 라이브러리는 대기상태에 빠져있어서 직접 close() 해줘야 했다.)2. 메세지처리기 만들기
TextWebSocketHandler 을 상속받는 클래스 생성
js 에서 들어오는 WebSocket 을 받는 handleTextMessage() 메서드를 override@Component : @Configuration 들이 @ComponentScan 로 빈으로 등록하는 어노테이션 중 최상위 @ComponentScan 이 스캔하여 Bean 등록하는 어노테이션 :
@Component 과 이에 포함된 @Repository, @Service, @Controller현재 쓰는 메세지처리기는 역할이 DAO(@Repository) 도 아니고 비지니스영역(@Service) 도 아니고 컨트롤(@Controller) 도 아니기 때문에
@Component 를 썼다.//연결 및 메세지 처리기 @Component public class MessageHandler extends TextWebSocketHandler{ @Override protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { //TextMessage payload=[ss], byteCount=2, last=true] 출력 System.out.println(message);//TextMessage 객체로 이 객체의 toString 이 실행되어 위처럼 출력됨 //session 의 sendMessage() 는 받은게 TextMessage 형이니 보낼 때도 TextMessage 형이다. //그래서 메세지 열만 TextMessage의 메서드인 getPayload() 로 String 형변환 후 //이 메세지만 꺼낸 String 을 다시 TextMessage 형변환 하여 보낸다. String 메세지만 = message.getPayload(); TextMessage 보낼message = new TextMessage(메세지만+"를 잘받았어"); session.sendMessage(보낼message); //연결처리 //메세지 처리 //끊기 처리 } }
3. 메세지처리기 등록
WebSocketConfigurer 을 구현한 클래스 생성
@Configuration @EnableWebSocket public class 웹소켓환경설정 implements WebSocketConfigurer{ @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(new MessageHandler(),"/chat"); } }
@Controller 와의 차이점 :
WebSocket 이 돌아갈 TextWebSocketHandler 을 상속받은 클래스는 요청명이 존재해도 컨트롤과는 달리
위에 RequestMapping 을 하는게 아니고
WebSocketConfigurer 구현한 클래스에서 직접 매핑을 시켜줌.
등록은 @ComponentScan 이 아니고 WebSocketConfigurer 의 클래스에서 add 하여 사용한다.4. web.xml 의 init-param 에 등록
<servlet> <servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextClass</param-name> <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value> </init-param> <init-param> <param-name>contextConfigLocation</param-name> <param-value> config.MvcConfig config.BeanConfig config.웹소켓환결설정 </param-value> </init-param> <load-on-startup>1</load-on-startup> <multipart-config> <location>/upload</location> <max-file-size>5242880</max-file-size><!--5MB--> <max-request-size>20971520</max-request-size><!--20MB--> <file-size-threshold>0</file-size-threshold> </multipart-config> </servlet>
WebSocket 으로 채팅 구현하기
1. client 상황 만들기(jsp 만들기)
<script> var 웹소캣; var 별명; function 연결하다(){ //연결이 여기에 있으니 이 함수를 적용한 버튼부터 눌러야 웹소켓이 생성되고 session 으로 저장된다. 웹소캣=new WebSocket("ws://localhost:8080/chat"); 웹소캣.onopen = function(){ let txt별명 = document.querySelector("#txt별명"); 별명 = txt별명.value; // json 문자열화 해서 보내기 웹소캣.send(JSON.stringify({'별명':별명,'상태':'입장'})); } 웹소캣.onmessage=function(result){ let 받은메세지 = result.data; let pMessage = document.querySelector("#pmessage"); pMessage.innerHTML=pMessage.innerHTML+"<br>"+받은메세지; } 웹소캣.onclose=function(){ 웹소캣 = null; } } function 보내다(){ let txtmessage = document.querySelector("#txtmessage"); 웹소캣.send(JSON.stringify({'별명':별명,'상태':'채팅',메세지:txtmessage.value})); } function 나가다(){ let txtmessage = document.querySelector("#txtmessage"); 웹소캣.send(JSON.stringify({'별명':별명,'상태':'퇴장')); } </script> </head> <body> 별병 <input type="text" id="txt별명"><br> <button onclick="연결하다()">연결</button><br> <button onclick="나가다()">나가기</button><br> 메세지 <input type="text" id="txtmessage"/><button onclick="보내다()">전송</button><br> <!-- p 태그처럼 <p></p> 로 닫히는 태그들만 innerHTML 이 있다. input 태그는 value 로 --> <p id="pmessage"></p> </body>
ws : websocket 의 프로토콜 임을 알림(http 처럼) 이 통신규약으로 spring 의 TextWebSocketHandler 로 통신하고 알아서 close()함 WebSocket : client 측의 socket 으로 연결을 걸 수는 있어도 받을 수는 없다.
( 연결을 거는 것이 메세지를 보내 답장을 받는 것이 아니고 처음에 통신연결을 거는것을 말한다. )
spring 에서는 이 소켓을 session 이라고도 부른다 (HttpSession 과는 이름은 같은 session 이라도 다 다르다.)
소켓을 처음에 받으면 session 을 저장하여 소켓이 계속 server 안에 있게 해야한다 (아래 예제)onopen : 연결이 되자마자 해당 함수 실행 send : 해당 웹소켓에 데이터 보냄 onmessage : 서버측에서 메세지가 오면(sendMessage()) 실행 2. json 객체를 받을 클래스 생성
public class 메세지Data { String 메세지; String 상태; String 별명; public String get메세지() { return 메세지; } public void set메세지(String 메세지) { this.메세지 = 메세지; } public String get상태() { return 상태; } public void set상태(String 상태) { this.상태 = 상태; } public String get별명() { return 별명; } public void set별명(String 별명) { this.별명 = 별명; } }
3. jsp 에서 메시지와 별명 등을 받아서 출력해줄 클래스
//연결 및 메세지 처리기 @Component public class MessageHandler extends TextWebSocketHandler{ List<WebSocketSession> 연결자들 = new ArrayList<WebSocketSession>(); //ws 프로토콜로 요청받을때마다 작동 @Override protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { String 메세지만 = message.getPayload();//json이 문자열화 된 것: "{별명: ,상태: ,}" ObjectMapper objectMapper = new ObjectMapper(); // readValue() : 지금까지 ajax 통신값인 json문자열을 @RequestBody 붙은 객체의 멤버변수에 알아서 들어갔듯이 // json 문자열을 해당 클래스의 멤버변수에 넣어주는 메서드 메세지Data 한메세지Data = objectMapper.readValue(메세지만, 메세지Data.class); TextMessage 보낼message = null; if(한메세지Data.get상태().equals("입장")) { 연결자들.add(session); 보낼message = new TextMessage(한메세지Data.get별명()+"님이 입장하였습니다."); }else if(한메세지Data.get상태().equals("채팅")) { 보낼message = new TextMessage(한메세지Data.get별명()+": "+한메세지Data.get메세지()); }else if(한메세지Data.get상태().equals("퇴장")) { 보낼message = new TextMessage(한메세지Data.get별명()+"님이 퇴장하였습니다."); } for(WebSocketSession webSocketSession:연결자들) { webSocketSession.sendMessage(보낼message); } //위의 매개변수인 session 은 List<WebSocketSession> 연결자들 처럼 모든 세션이 아니라 //이 요청을 한 본인만이다. if(한메세지Data.get상태().equals("퇴장")) { session.close(); 연결자들.remove(session); } //연결처리 //메세지 처리 //끊기 처리 } }
* 네트워크 형상관리 형상관리 : 소프트웨어 생명주기의 단계적 산출물에 대한 가시성과 추적가능성을 체계화하는 품질보증 활동이다.
( 어떤 프로그램이 수정될 때 버전을 업그레이드 시킨다는 뜻으로 보면 될 듯 )1. 의미
- 형상항목 : 버전을 바꿔야 할 대상 ( 버전을 관리할 대상 )
- 베이스라인 : 기준선 (무조건 버전을 바꿔주는 것이 아닌 이 기준을 보며 판단)
- 형상관리위원회 : 형상관리를 하는 곳 ( 팀내에서 팀장일 수도 있고 ..등등 )
- CMDB(Configuration Management Database) : 버전이 어떻게 바뀌었는지 이력을 저장함 ( 히스토리 )2. 프로세스
형상식별 -> 형상통제 -> 형상감사 -> 형상기록 의 절차를 가지고 있다.
- 형상식별 : 버전을 관리할 (변경할) 대상이 있구나 식별.
( 형상항목을 식별 )
- 형상통제 : 변경관리를 연계하여 수행해야 한다. 즉, 변경이 되었어도 그게 버전을 붙일만한 일인지 아직 그럴 정도의 변경이 아닌지 확인.
( 베이스라인이 쓰일 듯 하다. )
- 형상감사 : 변경사항을 확인하고 검토한다.
( 형상관리위원회가 체크할 거 같다. )
- 형상기록 : 형상관리한 히스토리를 남김
( CMDB가 쓰인다.)'JAVA' 카테고리의 다른 글
VO 와 DTO (0) 2021.08.03 Mock-test (0) 2021.07.27 3Tier: 예외처리,@Qualifier (0) 2021.07.27 Spring:interceptor,3Tier(Presentation,Business,Dataservice) (0) 2021.07.27 Mybatis:설정하기 (0) 2021.07.27