웹 소켓 단순 구현
인터넷 이 발전 함 에 따라 전통 적 인 HTTP 프로 토 콜 은 웹 응용 이 날로 복잡 해 지 는 수 요 를 만족 시 키 기 어렵다.최근 몇 년 동안 HTML 5 가 탄생 하면 서 웹 소켓 프로 토 콜 은 브 라 우 저 와 서버 의 모든 양 방향 통신 을 실현 하고 브 라 우 저 와 서버 의 통신 기능 을 확대 하여 서버 도 자발적으로 클 라 이언 트 에 데 이 터 를 보 낼 수 있 도록 했다.
우 리 는 전통 적 인 HTTP 프로 토 콜 이 무상 태 라 는 것 을 알 고 있 습 니 다. 매번 요청 (request) 은 클 라 이언 트 (예 를 들 어 브 라 우 저) 가 주동 적 으로 시작 해 야 합 니 다. 서버 가 처리 한 후에 response 결 과 를 되 돌려 주 고 서버 는 클 라 이언 트 에 데 이 터 를 주동 적 으로 보 내기 어렵 습 니 다.이러한 클 라 이언 트 는 주동 적 인 측 이 고 서비스 측은 수 동적 인 측의 전통 적 인 웹 모델 로 정보 변화 가 빈번 하지 않 은 웹 응용 에 있어 발생 하 는 번 거 로 움 이 비교적 적 으 며 실시 간 정보 와 관련 된 웹 응용 에 큰 불편 을 가 져 왔 다. 예 를 들 어 실시 간 통신, 실시 간 데이터, 구독 푸 시 등 기능 을 가 진 응용 이다.웹 소켓 규범 이 제기 되 기 전에 개발 자 들 은 이러한 실시 간 으로 비교적 강 한 기능 을 실현 하려 면 절충 적 인 해결 방법 인 폴 링 (polling) 과 Comet 기술 을 자주 사용한다.사실 후 자 는 본질 적 으로 도 일종 의 폴 링 으로 개선 되 었 을 뿐이다.
폴 링 은 실시 간 웹 응용 을 실현 하 는 가장 원시 적 인 해결 방안 이다.폴 링 기술 은 클 라 이언 트 가 설정 한 시간 간격 으로 주기 적 으로 서버 에 요청 을 보 내 고 새로운 데이터 변경 여 부 를 자주 조회 하도록 요구한다.이런 방법 은 불필요 한 요청 을 너무 많이 하고 데이터 와 서버 자원 을 낭비 하 는 것 이 분명 하 다.
Comet 기술 은 긴 폴 링 과 스 트림 기술 로 나 눌 수 있다.긴 폴 링 은 상술 한 폴 링 기술 을 개선 하여 쓸모없는 요 구 를 줄 였 다.일부 데이터 에 만 료 시간 을 설정 하고 데이터 가 만 료 된 후에 야 서버 에 요청 을 보 낼 수 있 습 니 다.이런 메커니즘 은 데이터 의 변경 에 적합 하 다. 특별히 빈번 한 상황 은 아니다.스 트림 기술 은 클 라 이언 트 가 숨겨 진 창 을 사용 하여 서버 와 HTTP 긴 연결 을 만 드 는 것 을 말 합 니 다. 서버 는 연결 상 태 를 계속 업데이트 하여 HTTP 긴 연결 을 유지 합 니 다.이렇게 하면 서버 는 이 긴 연결 을 통 해 자발적으로 데 이 터 를 클 라 이언 트 에 보 낼 수 있다.스 트림 기술 은 병발 환경 에서 서버 의 성능 을 시험 할 수 있다.
이 두 가지 기술 은 모두 요청 - 응답 모델 을 바탕 으로 하 는 것 으로 진정한 의미 의 실시 간 기술 이 아니다.그들의 모든 요청, 응답 은 똑 같은 머리 정보 에 일정한 데 이 터 를 낭비 하고 개발 의 복잡 도 도 비교적 크다.
HTML 5 가 출시 한 웹 소켓 과 함께 웹 의 실시 간 통신 을 진정 으로 실현 하여 B / S 모드 가 C / S 모드 의 실시 간 통신 능력 을 갖 추 게 되 었 다.웹 소켓 의 작업 절 차 는 다음 과 같 습 니 다. 브 라 우 저 는 자바 스 크 립 트 를 통 해 서버 에 웹 소켓 연결 을 요청 합 니 다. 웹 소켓 연결 이 성공 하면 클 라 이언 트 와 서버 는 TCP 연결 을 통 해 데 이 터 를 전송 할 수 있 습 니 다.웹 소켓 연결 은 본질 적 으로 TCP 연결 이기 때문에 전송 할 때마다 반복 되 는 머리 데 이 터 를 가 져 올 필요 가 없 기 때문에 폴 링 과 Comet 기술 보다 데이터 전 송 량 이 훨씬 적다.본 고 는 웹 소켓 규범 을 상세 하 게 소개 하지 않 고 주로 웹 소켓 이 자바 웹 에서 의 실현 을 소개 한다.
자바 EE 7 에서 JSR - 356: 자바 API for WebSocket 규범 이 나 왔 습 니 다.Tomcat, Nginx, Jetty 등 많은 웹 용기 들 이 웹 소켓 을 지원 한다.톰 캣 은 7.0.27 부터 웹 소켓 을 지원 하고 7.0.47 부터 JSR - 356 을 지원 하 며, 아래 데모 코드 역시 톰 캣 7.0.47 이상 에 배 치 된 버 전이 있어 야 실행 할 수 있다.
코드
pom 문서
javax
javaee-api
7.0
provided
백 엔 드 코드:
package com.websocket;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @ServerEndpoint , websocket ,
* URL , URL WebSocket
*/
@ServerEndpoint("/websocket/{clientId}")
public class WebSocket {
// , 。 。
private static AtomicInteger onlineCount = new AtomicInteger(0);
// concurrent Set, MyWebSocket 。
// , Map , Key
// private static CopyOnWriteArraySet webSocketSet = new
// CopyOnWriteArraySet();
// ,
// , map
//private Session session;
private static Map webSocketMap = new ConcurrentHashMap();
/**
*
*
* @param session 。session ,
*/
@OnOpen
public void onOpen(@PathParam("clientId") String clientId, Session session) {
// sessionId webSocket
String key = getWebSocketMapKey(clientId, session);
webSocketMap.put(key, session);
addOnlineCount(); // 1
System.out.println("WebSocket ! " + getOnlineCount());
}
/**
*
*/
@OnClose
public void onClose(@PathParam("clientId") String clientId, Session session, CloseReason closeReason) {
String key = getWebSocketMapKey(clientId, session);
webSocketMap.remove(key, session);
subOnlineCount(); // 1
System.out.println("WebSocket ! " + getOnlineCount());
}
/**
*
*
* @param message
* @param session
*/
@OnMessage
public void onMessage(@PathParam("clientId") String clientId, String message, Session session) {
System.out.println("WebSocket :" + message);
sendMessageByClientId(clientId, message);
}
/**
* webSocketMap Key
*
* @param clientId
* @param session webSocket Session
* @return
*/
private String getWebSocketMapKey(String clientId, Session session) {
if (StringUtil.isNil(clientId)) {
return session.getId();
} else {
return clientId + "_" + session.getId();
}
}
/**
*
*
* @param session
* @param error
*/
@OnError
public void onError(Session session, Throwable error) {
System.out.println("WebSocket ");
}
//
public static void doSend(String message) {
if (webSocketMap.size() > 0) {
for (Map.Entry entry : webSocketMap.entrySet()) {
try {
sendMessage(entry.getValue(), message);
} catch (IOException e) {
System.out.println("WebSocket doSend is error:");
continue;
}
}
}
}
public static void sendMessage(Session session, String message) throws IOException {
session.getBasicRemote().sendText(message);
}
public static int sendMessageByClientIdList(List clientIdList, String message) {
int status = 0;
for (String clientId : clientIdList) {
status = sendMessageByClientId(clientId, message);
}
return status;
}
/**
* webSocket
*
* @param clientId
* @param message
*/
public static int sendMessageByClientId(String clientId, String message) {
int status = 0;
if (webSocketMap.size() > 0) {
for (Map.Entry entry : webSocketMap.entrySet()) {
try {
String key = entry.getKey();
// webSocketMap clientId clientId
//
String key1 = key.substring(0, key.lastIndexOf("_"));
if (key1.equals(clientId)) {
sendMessage(entry.getValue(), message);
status = 200;
}
} catch (IOException e) {
System.out.println("WebSocket doSend is error:");
continue;
}
}
}
return status;
}
public static void sendSpeechMessageByClientId(String clientId, String message) {
if (webSocketMap.size() > 0) {
for (Map.Entry entry : webSocketMap.entrySet()) {
try {
String key = entry.getKey();
// webSocketMap clientId clientId
//
String key1 = key.substring(0, key.lastIndexOf("_"));
if (key1.equals(clientId)) {
sendMessage(entry.getValue(), message);
}
} catch (IOException e) {
System.out.println("WebSocket doSend is error:");
continue;
}
}
}
}
public static synchronized AtomicInteger getOnlineCount() {
return onlineCount;
}
public static synchronized void addOnlineCount() {
WebSocket.onlineCount.getAndIncrement();
}
public static synchronized void subOnlineCount() {
WebSocket.onlineCount.getAndDecrement();
}
}
전단 코드:
Java WebSocket Tomcat
Welcome
var websocket = null;
function connect() {
// WebSocket
if ('WebSocket' in window) {
var value = $("#b").val();
websocket = new WebSocket("ws://localhost:8080/ws/websocket/"+value);
//
websocket.onerror = function () {
setMessageInnerHTML("WebSocket ");
};
//
websocket.onopen = function () {
setMessageInnerHTML("WebSocket ");
}
//
websocket.onmessage = function (event) {
setMessageInnerHTML(event.data);
}
//
websocket.onclose = function () {
setMessageInnerHTML("WebSocket ");
}
// , , websocket , ,server 。
window.onbeforeunload = function () {
closeWebSocket();
}
}
else {
alert(' Not support websocket')
}
};
//
function setMessageInnerHTML(innerHTML) {
document.getElementById('message').innerHTML += innerHTML + '<br/>';
}
// WebSocket
function closeWebSocket() {
websocket.close();
}
//
function send() {
var message = document.getElementById('text').value;
websocket.send(message);
}
또한 웹 소켓 연결 을 만 들 면 http 응답 코드 는 101 입 니 다.
알림
1XX 시리즈 응답 코드 는 HTTP 서버 와 소통 할 때 만 사 용 됩 니 다.
이것 은 HTTP LBYL (look - before - you - leap) 요청 에 대한 가능 한 응답 입 니 다.이 응답 코드 는 클 라 이언 트 가 초기 요청 을 다시 보 내 고 요청 에 첫 번 째 요청 을 할 때 제공 하지 않 은 (크 거나 민감 한 정 보 를 포함 할 수 있 음) 표 시 를 첨부 해 야 한다 고 밝 혔 다.클 라 이언 트 가 이번에 보 낸 요청 은 거절 되 지 않 습 니 다.LBYL 요청 에 대한 또 다른 응답 은 417 ("Expectation Failed") 입 니 다.
요청 헤더: LBYL 요청 을 하려 면 클 라 이언 트 가 expect 요청 헤 더 를 문자열 '100 - continue' 로 설정 해 야 합 니 다.그 밖 에 클 라 이언 트 는 다른 헤더 도 설정 해 야 한다. 서버 는 이 헤더 에 따라 응답 100 인지 417 인지 결정 할 것 이다.
클 라 이언 트 가 요청 에서 Upgrade 헤 더 를 사용 하여 서버 에 HTTP 프로 토 콜 을 제외 한 다른 프로 토 콜 을 바 꾸 려 고 할 때 클 라 이언 트 는 이 응답 코드 를 받 습 니 다.101 응답 코드 는 "그래, 나 는 지금 다른 협 의 를 바 꾸 었 다" 고 표시 했다.보통 HTTP 클 라 이언 트 는 서버 로부터 101 응답 을 받 은 후 서버 와 의 TCP 연결 을 닫 습 니 다.101 응답 코드 는 이 클 라 이언 트 가 더 이상 HTTP 클 라 이언 트 가 아니 라 다른 클 라 이언 트 가 될 것 임 을 의미한다.업그레이드 헤 더 를 통 해 HTTP 에서 HTTPS 로 전환 하거나 HTTP 1.1 에서 미래의 버 전 으로 전환 할 수 있 지만 실제 업그레이드 헤 더 를 사용 하 는 경 우 는 적다.Upgrade 헤 더 는 HTTP 에서 완전히 다른 프로 토 콜 (예: IRC) 로 전환 하 는 데 도 사용 할 수 있 습 니 다. 그러나 웹 서버 에서 IRC 서버 로 전환 하 는 동시에 웹 클 라 이언 트 는 IRC 클 라 이언 트 로 전환 해 야 합 니 다. 서버 가 즉시 같은 TCP 연결 에서 새로운 프로 토 콜 을 사용 하기 시작 하기 때 문 입 니 다.
요청 헤더: 클 라 이언 트 는 Upgrade 헤 더 를 원 하 는 프로 토 콜 로 설정 합 니 다.응답 헤더: 서버 가 프로 토 콜 전환 에 동의 하면 Upgrade 헤더 로 돌아 가 프로 토 콜 로 전환 하고 빈 줄 을 첨부 합 니 다.서버 는 TCP 링크 를 닫 지 않 고 이 TCP 연결 에서 새 프로 토 콜 을 직접 사용 합 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
빠른 팁: SingleStoreDB의 데이터 API 사용SingleStoreDB는 HTTP 연결을 통해 SQL 문을 실행하는 데 사용할 수 있는 을 제공합니다. 이 짧은 문서에서는 이 데이터 API를 사용하는 방법에 대한 예를 보여줍니다. A는 무료 SingleStore...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.