|
|
|
@ -1,14 +1,12 @@
|
|
|
|
|
package com.baiye.server;
|
|
|
|
|
|
|
|
|
|
import cn.hutool.core.util.StrUtil;
|
|
|
|
|
import com.alibaba.fastjson.JSON;
|
|
|
|
|
import com.baiye.request.MessageRequest;
|
|
|
|
|
import io.netty.buffer.ByteBuf;
|
|
|
|
|
import io.netty.buffer.Unpooled;
|
|
|
|
|
import io.netty.channel.*;
|
|
|
|
|
import io.netty.handler.codec.http.DefaultFullHttpResponse;
|
|
|
|
|
import io.netty.handler.codec.http.FullHttpRequest;
|
|
|
|
|
import io.netty.handler.codec.http.HttpResponseStatus;
|
|
|
|
|
import io.netty.handler.codec.http.HttpVersion;
|
|
|
|
|
import io.netty.handler.codec.http.*;
|
|
|
|
|
import io.netty.handler.codec.http.websocketx.*;
|
|
|
|
|
import io.netty.util.CharsetUtil;
|
|
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
|
@ -22,7 +20,9 @@ import java.util.concurrent.ConcurrentHashMap;
|
|
|
|
|
import java.util.concurrent.Future;
|
|
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
|
|
|
|
|
|
import static io.netty.handler.codec.http.HttpResponseStatus.*;
|
|
|
|
|
import static io.netty.handler.codec.http.HttpUtil.isKeepAlive;
|
|
|
|
|
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @author Enzo
|
|
|
|
@ -62,12 +62,12 @@ public class SocketServerHandler extends SimpleChannelInboundHandler<Object> {
|
|
|
|
|
* @throws Exception
|
|
|
|
|
*/
|
|
|
|
|
@Override
|
|
|
|
|
protected void channelRead0(ChannelHandlerContext ctx, Object msg) {
|
|
|
|
|
protected void channelRead0(ChannelHandlerContext ctx, Object msg) {
|
|
|
|
|
|
|
|
|
|
if (msg instanceof FullHttpRequest){
|
|
|
|
|
if (msg instanceof FullHttpRequest) {
|
|
|
|
|
//以http请求形式接入,但是走的是websocket
|
|
|
|
|
handleHttpRequest(ctx, (FullHttpRequest) msg);
|
|
|
|
|
}else if (msg instanceof WebSocketFrame){
|
|
|
|
|
} else if (msg instanceof WebSocketFrame) {
|
|
|
|
|
//处理websocket客户端的消息
|
|
|
|
|
handlerWebSocketFrame(ctx, (WebSocketFrame) msg);
|
|
|
|
|
}
|
|
|
|
@ -101,7 +101,7 @@ public class SocketServerHandler extends SimpleChannelInboundHandler<Object> {
|
|
|
|
|
* @throws Exception
|
|
|
|
|
*/
|
|
|
|
|
@Override
|
|
|
|
|
public void handlerAdded(ChannelHandlerContext ctx) {
|
|
|
|
|
public void handlerAdded(ChannelHandlerContext ctx) {
|
|
|
|
|
log.info("一个客户端连接......" + ctx.channel().remoteAddress() + Thread.currentThread().getName());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -154,31 +154,39 @@ public class SocketServerHandler extends SimpleChannelInboundHandler<Object> {
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 唯一的一次http请求,用于创建websocket
|
|
|
|
|
* */
|
|
|
|
|
*/
|
|
|
|
|
private void handleHttpRequest(ChannelHandlerContext ctx,
|
|
|
|
|
FullHttpRequest req) {
|
|
|
|
|
//要求Upgrade为websocket,过滤掉get/Post
|
|
|
|
|
if (!req.decoderResult().isSuccess()
|
|
|
|
|
|| (!"websocket".equals(req.headers().get("Upgrade")))) {
|
|
|
|
|
//若不是websocket方式,则创建BAD_REQUEST的req,返回给客户端
|
|
|
|
|
sendHttpResponse(ctx, req, new DefaultFullHttpResponse(
|
|
|
|
|
HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST));
|
|
|
|
|
// Handle a bad request.
|
|
|
|
|
if (!req.decoderResult().isSuccess()) {
|
|
|
|
|
sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, BAD_REQUEST, Unpooled.EMPTY_BUFFER));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Allow only GET methods.
|
|
|
|
|
if (!HttpMethod.GET.equals(req.method())) {
|
|
|
|
|
sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, FORBIDDEN, Unpooled.EMPTY_BUFFER));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Handshake
|
|
|
|
|
//注意,这条地址别被误导了,其实这里填写什么都无所谓,WS协议消息的接收不受这
|
|
|
|
|
WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(
|
|
|
|
|
"ws://localhost:8099/websocket", null, false);
|
|
|
|
|
getWebSocketLocation(req), null, true, 5 * 1024 * 1024);
|
|
|
|
|
handShaker = wsFactory.newHandshaker(req);
|
|
|
|
|
if (handShaker == null) {
|
|
|
|
|
WebSocketServerHandshakerFactory
|
|
|
|
|
.sendUnsupportedVersionResponse(ctx.channel());
|
|
|
|
|
WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());
|
|
|
|
|
} else {
|
|
|
|
|
// 通过它构造握手响应消息返回给客户端,
|
|
|
|
|
// 同时将WebSocket相关的编码和解码类动态添加到ChannelPipeline中,用于WebSocket消息的编解码,
|
|
|
|
|
// 添加WebSocketEncoder和WebSocketDecoder之后,服务端就可以自动对WebSocket消息进行编解码了
|
|
|
|
|
handShaker.handshake(ctx.channel(), req);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 拒绝不合法的请求,并返回错误信息
|
|
|
|
|
* */
|
|
|
|
|
*/
|
|
|
|
|
private static void sendHttpResponse(ChannelHandlerContext ctx,
|
|
|
|
|
FullHttpRequest req, DefaultFullHttpResponse res) {
|
|
|
|
|
// 返回应答给客户端
|
|
|
|
@ -196,7 +204,7 @@ public class SocketServerHandler extends SimpleChannelInboundHandler<Object> {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void handlerWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame){
|
|
|
|
|
private void handlerWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) {
|
|
|
|
|
// 判断是否关闭链路的指令
|
|
|
|
|
if (frame instanceof CloseWebSocketFrame) {
|
|
|
|
|
handShaker.close(ctx.channel(), (CloseWebSocketFrame) frame.retain());
|
|
|
|
@ -219,10 +227,10 @@ public class SocketServerHandler extends SimpleChannelInboundHandler<Object> {
|
|
|
|
|
log.debug("服务端收到:" + request);
|
|
|
|
|
TextWebSocketFrame tws = new TextWebSocketFrame(new Date().toString()
|
|
|
|
|
+ ctx.channel().id() + ":" + request);
|
|
|
|
|
// channelHandlerContext.channel().writeAndFlush(tws);
|
|
|
|
|
// 返回【谁发的发给谁】
|
|
|
|
|
ctx.channel().writeAndFlush(tws);
|
|
|
|
|
|
|
|
|
|
ctx.channel().writeAndFlush(tws);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static Map<String, Channel> getChannelMap() {
|
|
|
|
|
return CHANNEL_MAP;
|
|
|
|
|
}
|
|
|
|
@ -234,4 +242,9 @@ public class SocketServerHandler extends SimpleChannelInboundHandler<Object> {
|
|
|
|
|
public static Map<String, Long> getClientMap() {
|
|
|
|
|
return CLIENT_MAP;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static String getWebSocketLocation(FullHttpRequest req) {
|
|
|
|
|
String location = req.headers().get(HttpHeaderNames.HOST) + req.uri();
|
|
|
|
|
return "ws://" + location;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|