통합 웹 소켓 두 구현 springboot

기존의 HTTP 웹 소켓 프로토콜과 차이점, 장점과 단점은 여기에 설명 된 아마

A, 웹 소켓 및 HTTP 

응용 프로그램 계층 프로토콜에서 사용되는 HTTP 프로토콜은, 그가 TCP 프로토콜을 기반으로, 링크를 설정하기 위해 HTTP 프로토콜은 메시지를 보낼 수있는 세 방향 핸드 셰이크가 있어야합니다. HTTP 링크는 짧은 세 방법은 자신의 정보를 전송하는 각 요청을 핸드 셰이크입니다, 짧은 링크, 긴 링크로 연결합니다. 즉, 각각의 응답 요청에 대응한다. 긴 링크 링크는 일정 기간 내에서 유지된다. 열린 TCP 연결을 유지하기 위해 계속합니다. 클라이언트는 서버에서 시작되어야합니다 클라이언트가 다음 결과를 반환, 서버와 통신합니다. 클라이언트는 서버가 수동이다 활성화됩니다. 
HTML5 웹 소켓은 일치한다, 그가 태어난 회전에 문제가 오랜 기간을 통해 이동해야하는 서버 리소스 브라우저에 여러 HTTP 요청을 시작하는 클라이언트를 해결하는 것입니다, 그는 다중화를 실현, 그는 전이중 (full-duplex) 통신이다. 고객과 브라우저를 종료는 웹 소켓 프로토콜에서 동시에 정보를 전송할 수있다.

둘째, 오래 지속 연결은 HTTP 웹 소켓에 연결되어

HTTP1.1 기본 긴 링크 연결 (영구 연결)

즉,이 특정 제한 시간 내에 연결 상태를 유지, 클라이언트는, 짧은 시간에 서버에 많은 자원을 요청 열려있는 TCP 연결을 유지하기 위해 계속해야합니다. 클라이언트는 서버에서 시작되어야합니다 클라이언트가 다음 결과를 반환, 서버와 통신합니다. 클라이언트는 서버가 수동이다 활성화됩니다.

  본질적으로 여전히 / 응답 메시지는 여전히 자원의 낭비가 될 것이다 요청하기 때문에 여러 요청 / 응답 메시지를 전송할 수있는 TCP 연결에서 실시간 성능은 강력하고 다른 문제 없습니다.

짧은 연결, 각 리소스는 새 연결을 설정해야하지 지속적인 연결이 HTTP가 기본 TCP에 의해 사용되는 경우, 때마다 당신은 발생합니다, 각 요청에 대한 응답에 해당하는, 즉, TCP 연결을 설정하는 세 방향 핸드 셰이크를 사용 자원의 큰 낭비.

  롱 폴링, 즉, 클라이언트는 긴 시간 제한 요청, 새로운 데이터가 도착했을 때, 응답이 라이브 반환 개최 연결 서버를 전송

단지 요청 / 응답 메시지를 확립하기 위해 필요한 여러 번 헤더 정보의 중복을 생성 피하고, 모든 TCP 연결 후 요청 / 응답 메시지의 영구 연결을 생성, 웹 소켓.

웹 소켓 HTTP 악수를 한 번만, 전체 통신 과정은 연결 / 상태에 따라, 그리고 서버가 불가능 HTTP 인 클라이언트를, 연락 주도권 WebSocket을 달성 할 수 있도록.

다른 구현의 웹 소켓의 springboot 통합 :

치어 종속성을 추가


<의존성>
<의 groupId> org.springframework.boot </를의 groupId>
<artifactId를> 초보자 - 스프링 - 부트 웹 소켓 <artifactId를 />
</ 의존성>
 는 해당 HTML을 작성하므로, 서버에 접속 JS를 포함 이 일이해야 할 모든 전에 프로젝트의 프론트 엔드의 분리 후, thymeleaf 템플릿에서 통합


<의존성>
<의 groupId> org.springframework.boot </의 groupId>
<artifactId를> 스프링 부팅 스타터 thymeleaf </ artifactId를>
</ 의존성>
配置文件:

서버 :
포트 : 8885

#添加Thymeleaf配置
thymeleaf :
캐시 : 거짓
접두사 : 클래스 경로 : / 템플릿 /
접미사 : .html 중에서
모드 : HTML5
인코딩 : UTF-8
의 Content-Type : text / html과
 

1 : 사용자 WebSocketServer, 기본 웹 소켓 사용 방법은, 대응으로 onOpen,으로 onClose,의 onMessage,의 OnError 방법을 제공하는

1.1 : 추가 webSocketConfig 구성 클래스

/ **
* 오픈 지원 웹 소켓은
* 2019년 5월 31일 ON huiyunfei에 의해 만들어진.
* /
@Configuration
공용 클래스 WebSocketConfig {
@Bean
공공 ServerEndpointExporter의 serverEndpointExporter는 () {
새로운 새로운 ServerEndpointExporter ()를 호출;
}
}
1.2 : 서버 클래스 webSocketServer 추가

com.example.admin.web 패키지;

/ **
* 2019년 5월 31일 온 huiyunfei에 의해 만들어진.
* /

@ServerEndpoint ( "/ 웹 소켓 / {SID}")
@Component
@ SLF4J
공용 클래스 WebSocketServer {
// 정적 변수, 열려있는 연결의 현재 수를 기록하는 데 사용. 스레드 안전하도록 설계되어야한다.
정적 INT = 0 개인 onlineCount;
// 동시 보안 스레드 패키지 세트, MyWebSocket 각 클라이언트에 해당하는 객체를 저장하는 데 사용됩니다.
정적 CopyOnWriteArraySet 개인 <WebSocketServer> webSocketSet 새로운 새로운 CopyOnWriteArraySet = <WebSocketServer> ();

클라이언트에 대한 연결 세션과는 // 클라이언트를 통해 데이터를 전송해야
개인 세션 세션을;

//이 SID받은
= ""개인 SID 문자열;


* /
/ **
* // * *라는 성공적인 방법을 확립 연결
@OnOpen
{공공 무효으로 onOpen (세션 세션, @PathParam ( "SID") 문자열 SID)를
세션 = this.session,
webSocketSet.add는합니다 (이)에 참여하도록 설정 //
addOnlineCount (); // 온라인 플러스 1
log.info ( "새 창이 듣고 시작 :"+ SID + ", 현재 행 번호는"+ getOnlineCount는 ());
this.sid = SID;
은 try {
및 SendMessage는 ( "연결 성공");
} 캐치 (IOException가 E) {
log.error ( "웹 소켓 입출력 예외");
}
}
* /
/ **
* 전화 연결이 닫힙니다 방법
* // *
@OnClose
공공 무효으로 onClose () {
webSocketSet.remove합니다 (이); //의 세트에서 삭제
subOnlineCount은 (); // 온라인 마이너스 1
log.info ( "온라인의 현재 수에 밀접한 관련이있다! "+ getOnlineCount ());
}
* /
/ **
* 메시지의 수신 종료 후에 클라이언트 호출 방법
*
@param 메시지가 클라이언트 // *에 의해 전송되는 메시지 *
@OnMessage
의 onMessage 공개 (문자열 메시지, 세션 세션) {무효
log.info ( "정보" "창에서받는"메시지 + + + SID);
// 그룹 메시지
(WebSocketServer 항목 : webSocketSet)에 대한 {
은 try {
item.sendMessage ( 메시지);
} 캐치 (IOException가 E) {
e.printStackTrace ();
}
}
}
* /
/ **
*
* @param 세션
*의 @param 오류
* // *
@OnError
공공 무효의 OnError (세션 세션의의 Throwable 에러) {
log.error ( "오류");
error.printStackTrace는 ();
}
* /
/ **
* 푸시 서버는 적극적으로 구현
*은 //을 *
공공 무효 및 SendMessage (문자열 메시지) IOException가 {던졌습니다
this.session.getBasicRemote () sendText (메시지);
}
* /
/ **
* 대량 사용자 정의 메시지
* * * //
공공 정적 무효 sendInfo (문자열 메시지, PathParam @ ( "SID") 문자열 SID)는 IOException가 {던졌습니다
; log.info (+ 메시지 "창에 푸시 메시지"+ SID + ", 푸쉬 컨텐트")
{: (webSocketSet WebSocketServer 항목)에 대한
은 try {
//에만 모든 밀어 널에 SID를 밀어 수 있습니다 여기에서 설정
IF (SID == NULL) {
item.sendMessage (메시지);
}는 다른 IF (item.sid.equals가 (SID)) {
item.sendMessage (메시지);
}
} 캐치 (IOException이 E가) {
계속;
}
}
}
공개 INT는 동기화 정적 getOnlineCount () {
onlineCount를 반환;
}
공공 정적 동기화 무효 addOnlineCount () {
WebSocketServer.onlineCount ++;
}
공공 정적 동기화 무효 subOnlineCount () {
WebSocketServer.onlineCount--;
}
공공 정적 CopyOnWriteArraySet <WebSocketServer> getWebSocketSet () {
webSocketSet를 리턴;
}
}
1.3 :添加对应的컨트롤러

@Controller
@RequestMapping ( "/ 시스템")
공용 클래스 SystemController {
//页面请求
@GetMapping ( "/ 인덱스 / {userId를}")
공공의 ModelAndView 소켓 (@PathVariable 문자열 사용자 ID) {
의 ModelAndView MAV = 새의 ModelAndView ( "/ socket1" );
mav.addObject ( "userId를", userId를);
MAV를 반환;
}
//推送数据接口
@ResponseBody
@RequestMapping ( "/ 소켓 / 푸시 / {CID}")
공개지도 pushToWeb (@PathVariable 문자열 CID, 문자열 메시지) {
지도 결과 = 새의 HashMap ();
시도 {
WebSocketServer.sendInfo (메시지, CID);
result.put ( "코드", 200);
result.put ( "MSG", "성공");
} 캐치 (IOException이 전자) {
전자. printStackTrace에 ();
}
결과 반환;
}
 1.4 : 페이지 socket1.html을 제공

<! DOCTYPE HTML>
<HTML LANG = "EN">
<head>
<메타 문자 집합 = "UTF-. 8"> </ 메타>
<제목> 제목 </ 제목>
</ head>
<body>
안녕하세요!

</ BODY>
<script>
var에 소켓;
IF (대해서 typeof (웹 소켓은) == "정의되지 않은이") {
을 console.log는 ( "웹 소켓을 지원하지 않는 브라우저");
} {다른
을 console.log는 ( "브라우저가 지원하는 웹 소켓 「)
// 웹 소켓 연결을 설정하기 위해 포트에 접속되는 서버의 어드레스를 특정 목적을 달성
// 등가
WS를 (인덱스 = 새로운 새로운 웹 소켓을 ": // 로컬 호스트 : 8885 / 웹 소켓 / 2");
// 새로운 새로운 소켓 = 웹 소켓 ( "$ {basePath 웹 소켓} / $ {CID는}"는이) ( "HTTP", "WS"를 대체합니다.);
// 이벤트 열
인덱스를.함수의 OnOpen = () {
CONSOLE.LOG ( "개방 소켓");
//socket.send ( "이것은 클라이언트로부터의 메시지이다"+ + 같이 location.href 새로운 날짜 () );
}
// 메시지 이벤트 얻을
index.onmessage = 함수 (MSG) {
CONSOLE.LOG (msg.data)
트리거 로직의 선단에 발견 메시지 처리를 시작을 //
}
// 근접 이벤트
index.onclose = 함수 () {
콘솔 .LOG는 ( "소켓이 닫혀");
};
// 오류가 발생했습니다 이벤트
index.onerror = 함수 () {
경고 ( "소켓 오류가 발생했습니다");
//이 시점에서 페이지를 다시 시도 할 수
}
페이지를 떠날 때 // 닫기 소켓
폐기 된 //jquery1.8가 3.0 제거한
// $ (창) .unload (함수 () {
// Socket.close ();
//});
}
</ script>
< / HTML>
 요약 :

브라우저가 디버그 로컬 호스트에 액세스 할 수 : 8,885 / 시스템 / 인덱스에게 / 1 점프를 socket1.html하기 위해 서버에 연결하고 자동으로 서버 CID로 전송 JS 페이지에 해당하는 클라이언트에 푸시 메시지 서버 (CID 서버에서 다른 요청을 구분 방법이 제공된다 입력 메시지)

2.1 : 웹 소켓 프로토콜을 기반으로 STOMP

STOMP를 사용의 장점은 완전히 메시지 큐 모드, 당신은 그것을 인식하는 생산자의 메시지를 보내 생산자와 소비자의 아이디어를 사용하여, 소비자가 메시지를받을 것입니다. 이 경우 소비자는 개발자가 이러한 구독을 푸시 대상으로 이전의 관계를 관리 할 필요가 없습니다, 다른 대상에 가입 할 수있는 다른 푸시 메시지를 얻기 위해, 봄의 공식 웹 사이트는 스톰 - 데모의 단순 온천 부팅이 기반 springboot, 당신은 위의 봄 튜토리얼을 기반으로 간단한 데모를 작성하려고 할 수 있습니다.

 

websocketConfig 구성 클래스를 제공합니다

/ **
* @description :
registerStompEndpoints (StompEndpointRegistry 레지스트리)
configureMessageBroker (MessageBrokerRegistry의 설정)
이 방법의 효과는 사양 정보에 대한 다양한 인기있는 것은 연결 요청 메시지에 제공되는 메시지 브로커를 정의하는 것입니다.
registry.enableSimpleBroker ( "/ 항목") 클라이언트 구독 주소 접두사 정보, 즉, 클라이언트가 (아마 이해할 수있을 것입니다, 전체 예제를 읽고, 주위 비교) 주소 접두사 정보 서비스 종료 메시지를 수신합니다
(registry.setApplicationDestinationPrefixes를 접두사 서버가 의미하는 주소 접두사를 수신에 "/ 응용 프로그램")가 참조하는 서버 메시지 주소로 클라이언트
*의 @author : [email protected]
* @date : 2019년 5월 31일
* /
@ 구성
@EnableWebSocketMessageBroker
공공 클래스를 WebSocketConfig는 AbstractWebSocketMessageBrokerConfigurer가 {확장

//이 방법의 효과는 수신 클라이언트에 연결된 서비스 엔드 포인트를 추가하는 것입니다.
// registry.addEndpoint ( "/ 소켓") A / 소켓 엔드 포인트를 추가 나타내며, 클라이언트는이 엔드 포인트를 통해 연결할 수 있습니다.
// withSockJS () 역할 SockJS 지원을 열 수 있습니다,
@Override
공개 무효 registerStompEndpoints (StompEndpointRegistry 레지스트리) {
registry.addEndpoint ( "/ 소켓") withSockJS는 ();
}
@Override
공개 무효 configureMessageBroker은 (MessageBrokerRegistry 레지스트리) {
// 프리픽스 즉, 클라이언트가 클라이언트의 가입 어드레스 정보를 나타내고, 어드레스 프리픽스 정보 서버 메시지 수신
registry.enableSimpleBroker ( "/ 토픽");
// 즉, 어드레스를 수신하고 상기 서비스 수단 프리픽스하는 서버 어드레스에 클라이언트 메시지
registry.setApplicationDestinationPrefixes ( "/ 앱 ")는;
}는
}
 2.2 : 컨트롤러는 요청에 대응하는 인터페이스를 제공한다

// 페이지 요청
@GetMapping ( "/ SOCKET2")
공공의 ModelAndView SOCKET2 () {// PathVariable @ 문자열 사용자 ID
의 ModelAndView 새로운 새의 ModelAndView MAV = ( "HTML / SOCKET2");
//mav.addObject("userId "사용자 ID);
MAV 반환;
}

/ **
* @description :이 방법은 @MessageMapping를 사용하여 클라이언트 요청 전원 웹 소켓 발표에서 보낸
* @author : [email protected]
* @date : 2019년 5월 31일
* /
클라이언트 설정 서버가 서버에 액세스하는 것은 또한 예제를 추가해야 할 때 접두사를 수신하도록 구성 @MessageMapping ( "/ 변경 - 공지 사항") // : / 응용 프로그램 / 변경 Notice-
@SendTo ( "/ 주제 / 공지 사항") / / config에 추가 기억 구성된 접두사를 구독
인사말 (CUSTOMMESSAGE 메시지) 공공 CUSTOMMESSAGE를 {
;에서 System.out.println이 (+ ()가 message.toString "서버는 메시지 수신")
// 우리는이 방법 메시지를 사용을 전달 보냈습니다!
//this.simpMessagingTemplate.convertAndSend("/topic/notice ", 값) (정기적으로 타이머)를 사용하여 클라이언트에게 메시지를 보낼 수 있습니다
// @Scheduled (FIXEDDELAY = 1000L)
// 공공 무효 시간 () {
// messagingTemplate을 .convertAndSend ( "/ 시스템 / 시간"새로운 새로운 날짜의 toString () ().);
//}
//있는 sendto 사용하여 전송 될 수있다
반환 메시지;
}
2.3 : 제공 socket2.html

<! DOCTYPE HTML>
<HTML XMLNS : = "http://www.thymeleaf.org"일>
<head>
<메타 문자 집합 = "UTF-8"/>
<제목> 봄 부팅 + 웹 소켓 +广播式</ 제목>

</ head>
<body의 온로드 = "해제 ()">
<NOSCRIPT> <H2 스타일 = "색상 : #의 FF0000">貌似你的浏览器不支持웹 소켓 </ H2> </ NOSCRIPT>
<DIV>
<DIV>
<버튼 ID가 =의 onclick = "connect ()가 「"연결 ">连接</ 버튼>
<버튼 ID ="단절 "비활성 ="금지 "의 onclick ="연결 해제 (); ">断开连接</ 버튼>
< / div>
<div ID = "conversationDiv">
<라벨>输入你的名字</ 라벨> <input 타입 = "텍스트 "ID ="이름 "/>
<버튼 ID ="sendName "의 onclick ="sendName (); ">发送</ 버튼>
<p의 ID ="응답 "> </ p>
</ div>
</ div>
<스크립트 일 : SRC = "@ {/의 JS / sockjs.min.js}"> </ script>
<script 일 : SRC = "@ {/의 JS / stomp.min.js}"> </ script>
<script 일 : SRC = "@ {/ JS / JQuery와-3.2.1.min.js}"> </ script>
<스크립트 유형 = "텍스트 / 자바 스크립트">
var에 stompClient = NULL;

함수 setConnected (접속) {
document.getElementById를 ( '연결') 장애인 = 접속되어있다.;
document.getElementById를 ( '분리')가 비활성화 = 연결되어 있습니다.!
document.getElementById를 ( 'conversationDiv'). style.visibility = 접속? '볼': '숨겨진';
$ ( '# 응답') HTML ().;
}

함수 () {연결
VAR 소켓 새로운 SockJS = ( '/ 소켓'); // 1
stompClient = 구르기.


CONSOLE.LOG ( '开始进行连接연결'+ 프레임);
stompClient.subscribe ( '/ 주제 / 통지'기능 (respnose) {// 4
showResponse (JSON.parse (respnose.body) .responseMessage)
});
});
}


함수 차단 () {
경우 (stompClient = NULL!) {
stompClient.disconnect ();
}
setConnected (FALSE);
CONSOLE.LOG ( "끊김");
}

기능 sendName () {
var에 이름 = $ ( '# 이름') 발 ().;
stompClient.send ( "/ 응용 프로그램 / 변화 예고", {}, JSON.stringify ({ '이름'이름})); // 5
}

기능 showResponse (메시지) {
var에 응답 = $ ( "# 응답") ;
response.html (메시지);
}
</ SCRIPT>

</ HTML>
2.4 : 해당 참조 온라인 다운로드 JS 갈 수있다

2.5 : 브라우저가 디버그 로컬 호스트에 액세스 할 수 : 8,885 / 시스템 / socket2을 서버에 연결을 클릭, 데이터 콘텐츠는 메시지 서버에 푸시 할 수 있으며, 서버가 다시 푸시됩니다.

2.6 : 회전 훈련 프런트 엔드를 구현하고 서버 페이지 아약스 회전도 백 - 엔드 타이머를 추가 할 수 있습니다

@Component
@EnableScheduling
Public 클래스 TimeTask {
개인 정적 로거 로거 = LoggerFactory.getLogger (TimeTask.class)

@Scheduled ( "? 0/20 * * * *"크론 =)
공공 무효 테스트 () {
System.err.println을 ( "********* 예약 태스크 실행 **************");
CopyOnWriteArraySet는 <WebSocketServer> webSocketSet =
WebSocketServer.getWebSocketSet ()
= 0 인 I를 나타내는 int
webSocketSet.forEach을 (C -> {
은 try가 {
c.sendMessage는 ( "전송"+ 새로운 새로운 날짜 () toLocaleString ());
} 캐치 (IOException가 E) {
e.printStackTrace ();
}
});

System.err.println을 ( " / n은 타이밍 작업 완료 ....... ");
}
}
코드 https://github.com/huiyunfei/spring-cloud.자식 관리자의 프로젝트

브로드 캐스트 모드 및 애드혹 모드 STOMP 프로토콜 메시지를 푸시하는 것은 기준에 근거 할 수있다 :
https://www.cnblogs.com/hhhshct/p/8849449.html

https://www.cnblogs.com/jmcui/p/8999998.html
----------------
면책 조항 :이 문서에서 "마오를 Touxing하지"CSDN 원래의 블로거 기사에 의해-SA 저작권 계약, 복제, 원본 소스 링크이 문을 첨부하시기 바랍니다 CC 4.0을 따릅니다.
원본 링크 : HTTPS : //blog.csdn.net/huiyunfei/article/details/90719351

추천

출처www.cnblogs.com/Jeremy2001/p/11525082.html