웹소켓 프로토콜 판단, 악수 및 피드백
긴 연결을 하려면 먼저 클라이언트가 서버와의 악수 동작을 시작해야 한다. 다음은 위키백과에서 찾은 예이다.
브라우저 요청:
GET /demo HTTP/1.1
Host: example.com
Connection: Upgrade
Sec-WebSocket-Key2: 12998 5 Y3 1 .P00
Sec-WebSocket-Protocol: sample
Upgrade: WebSocket
Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5
Origin: http://example.com
^n:ds[4U
요청에 있는 "Sec-WebSocket-Key1", "Sec-WebSocket-Key2", 마지막 "^n:ds[4U"는 랜덤입니다. 서버 측은 이 데이터로 16바이트의 응답을 구성합니다. 그 중에서: ^n:ds[4U는 요청한 내용입니다. 다른 것은 http 요청 헤더입니다.
주: Sec-WebSocket-Key1과 Sec-WebSocket-Key2는 낡은 웹소켓 프로토콜에 없습니다. 현재 요청이 웹소켓인지 아닌지를 판단하기 때문입니다. 주로 요청 헤더의 연결이 업그레이드인지, 업그레이드가 웹소켓인지 여부를 판단하기 때문입니다. 즉, 하나의 요청이 웹소켓인지 아닌지를 판단하려면 요청 헤더의 연결과 업그레이드만 판단하면 됩니다.새 버전은 Sec-WebSocket-Key1과 Sec-WebSocket-Key2를 포함할 수 있는지 여부를 판단합니다.다음은 웹소켓 요청 여부를 판단하는 코드입니다.
// : Netty
private boolean isWebSocketReq(HttpRequest req) {
return (HttpHeaders.Values.UPGRADE.equalsIgnoreCase(req.getHeader(HttpHeaders.Names.CONNECTION)) && HttpHeaders.Values.WEBSOCKET.equalsIgnoreCase(req.getHeader(HttpHeaders.Names.UPGRADE)));
}
서버 응답:
HTTP/1.1 101 WebSocket Protocol Handshake
Upgrade: WebSocket
Connection: Upgrade
Sec-WebSocket-Origin: http://example.com
Sec-WebSocket-Location: ws://example.com/demo
Sec-WebSocket-Protocol: sample
8jKS’y:G*Co,Wxa-
요청한 첫 번째 키의 숫자를 첫 번째 키의 공백 문자로 나누고, 두 번째 키도 마찬가지다.그리고 이 두 결과를 요청의 마지막 8바이트 문자열과 연결시켜 하나의 문자열로 만들고, 서버 응답 본문 ("8jKS'y:G*Co, Wxa-") 즉 이 문자열의 MD5sum입니다.Netty 기반 응답 JAVA 코드는 다음과 같습니다. // Netty WEBSOCKET
private HttpResponse buildWebSocketRes(HttpRequest req) {
HttpResponse res = new DefaultHttpResponse(HttpVersion.HTTP_1_1,
new HttpResponseStatus(101, "Web Socket Protocol Handshake"));
res.addHeader(HttpHeaders.Names.UPGRADE, HttpHeaders.Values.WEBSOCKET);
res.addHeader(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.UPGRADE);
// Fill in the headers and contents depending on handshake method.
if (req.containsHeader(Names.SEC_WEBSOCKET_KEY1) && req.containsHeader(Names.SEC_WEBSOCKET_KEY2)) {// 7.5、7.6
// New handshake method with a challenge:
res.addHeader(Names.SEC_WEBSOCKET_ORIGIN, req.getHeader(Names.ORIGIN));
res.addHeader(Names.SEC_WEBSOCKET_LOCATION, getWebSocketLocation(req));
String protocol = req.getHeader(Names.SEC_WEBSOCKET_PROTOCOL);
if (protocol != null) {
res.addHeader(Names.SEC_WEBSOCKET_PROTOCOL, protocol);
}
// Calculate the answer of the challenge.
String key1 = req.getHeader(Names.SEC_WEBSOCKET_KEY1);
String key2 = req.getHeader(Names.SEC_WEBSOCKET_KEY2);
int a = (int) (Long.parseLong(getNumeric(key1)) / getSpace(key1).length());
int b = (int) (Long.parseLong(getNumeric(key2)) / getSpace(key2).length());
long c = req.getContent().readLong();
ChannelBuffer input = ChannelBuffers.buffer(16);
input.writeInt(a);
input.writeInt(b);
input.writeLong(c);
ChannelBuffer output = null;
try {
output = ChannelBuffers.wrappedBuffer(MessageDigest.getInstance("MD5").digest(input.array()));
} catch (NoSuchAlgorithmException e) {
logger.error("no such Algorithm : MD5. ", e);
}
res.setContent(output);
} else {// websocket
// Old handshake method with no challenge:
if (req.getHeader(Names.ORIGIN) != null) {
res.addHeader(Names.WEBSOCKET_ORIGIN, req.getHeader(Names.ORIGIN));
}
res.addHeader(Names.WEBSOCKET_LOCATION, getWebSocketLocation(req));
String protocol = req.getHeader(Names.WEBSOCKET_PROTOCOL);
if (protocol != null) {
res.addHeader(Names.WEBSOCKET_PROTOCOL, protocol);
}
}
return res;
}
//
private String getNumeric(String str) {
return str.replaceAll("\\D", "");
}
//
private String getSpace(String str) {
return str.replaceAll("\\S", "");
}
후기:
최근 크롬14 및 FF6.5에서 최신 웹소켓 초안 10 프로토콜을 사용한 것을 발견했다. 즉, 위의 예시된 코드는 초안 10의 악수 프로토콜을 지원하지 못한다. 초안 손의 프로토콜 변수가 비교적 크다. 예를 들어 전송은 프레임을 통해 이루어지고 프레임의 위치를 검사할 권리가 있다는 등이다. 상세하게 나의 다른 글을 볼 수 있다.http://blog.csdn.net/fenglibing/article/details/6852497
풍립빈의 블로그
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
하나의 수조를 깊이가 가장 낮은 두 갈래 나무로 바꾸다문제 정의: Givena sorted(increasing order) array, write an algorithm to create abinary tree with minimal height. 생각: 이 문제는 비...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.