基于Netty最简单的WebSocket通讯_binarywebsocketframe-程序员宅基地

技术标签: Netty  消息协议  Http  WebSocket  

基于Netty最简单的WebSocket通讯

总览

  1. 总共是五个文件:
    • client
      • EasyWsClient 客户端
      • EasyWsClientHandler 客户端消息处理类
    • server
      • EasyWsServer 服务端
      • EasyWsServerHandler 服务端消息处理类
    • EasyWsTest 测试类

  2. EasyWsServer启动时需要声明一个ServerBootstrap,ServerBootstrap里面初始化需要添加一个handler。

  3. WebSocket通讯和普通的tcp通讯不同的是,他有2个格式的消息需要处理
    • 流程:
      • http请求握手
      • 握手完成后的长连接通讯
    • 消息
      • http消息,如:FullHttpRequest、FullHttpResponse等
      • websocket消息,如TextWebSocketFrame(文本类消息),BinaryWebSocketFrame(字节类数据)等

  4. 客户端第一次发送http握手请求的时候,需要使用WebSocketClientHandshaker
  5. 里面处理了文本消息,二进制字节消息。

服务端

EasyWsServer

/*
 * Copyright (C), 2015-2018
 * FileName: EasyWsServer
 * Author:   zhao
 * Date:     2018/8/14 10:43
 * Description: 简单的WebScoket服务器
 * History:
 * <author>          <time>          <version>          <desc>
 * 作者姓名           修改时间           版本号              描述
 */
package com.lizhaoblog.demopro.websocket.server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.stream.ChunkedWriteHandler;

/**
 * 〈一句话功能简述〉<br>
 * 〈简单的WebScoket服务器〉
 *
 * @author zhao
 * @date 2018/8/14 10:43
 * @since 1.0.1
 */
public class EasyWsServer {
    
  private int port;

  public EasyWsServer(int port) {
    this.port = port;
  }

  public void start() throws InterruptedException {
    ServerBootstrap serverBootstrap = new ServerBootstrap();
    EventLoopGroup bossGroup = new NioEventLoopGroup();
    EventLoopGroup workerGroup = new NioEventLoopGroup();
    serverBootstrap.group(bossGroup, workerGroup);
    serverBootstrap.channel(NioServerSocketChannel.class);
    serverBootstrap.childHandler(new ChannelInitializer() {
      @Override
      protected void initChannel(Channel channel) throws Exception {
        ChannelPipeline pipeline = channel.pipeline();
        pipeline.addLast("http-codec", new HttpServerCodec()); // Http消息编码解码
        pipeline.addLast("aggregator", new HttpObjectAggregator(65536)); // Http消息组装
        pipeline.addLast("http-chunked", new ChunkedWriteHandler()); // WebSocket通信支持
        pipeline.addLast(new EasyWsServerHandler());
      }
    });

    // 监听端口
    ChannelFuture channelFuture = serverBootstrap.bind(port).sync();
    channelFuture.awaitUninterruptibly();
    // 堵塞线程,保持长连接
    channelFuture.channel().closeFuture().sync();
  }

}

EasyWsServerHandler

/*
 * Copyright (C), 2015-2018
 * FileName: EasyWsServerHandler
 * Author:   zhao
 * Date:     2018/8/14 10:44
 * Description: 简单的WebSocket服务器
 * History:
 * <author>          <time>          <version>          <desc>
 * 作者姓名           修改时间           版本号              描述
 */
package com.lizhaoblog.demopro.websocket.server;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpUtil;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerHandshaker;
import io.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory;
import io.netty.util.CharsetUtil;

/**
 * 〈一句话功能简述〉<br>
 * 〈简单的WebSocket服务器〉
 *
 * @author zhao
 * @date 2018/8/14 10:44
 * @since 1.0.1
 */
public class EasyWsServerHandler extends SimpleChannelInboundHandler<Object> {
  @Override
  protected void channelRead0(ChannelHandlerContext channelHandlerContext, Object msg) throws Exception {
    if (msg instanceof FullHttpRequest) {
      // 传统的HTTP接入
      handleHttpMessage(channelHandlerContext, msg);
    } else if (msg instanceof WebSocketFrame) {
      // WebSocket接入
      handleWebSocketMessage(channelHandlerContext, msg);
    }

  }

  /**
   * 处理WebSocket中的Http消息
   *
   * @param ctx 上下文
   * @param msg 消息
   */
  private void handleHttpMessage(ChannelHandlerContext ctx, Object msg) {
    // 传统的HTTP接入
    FullHttpRequest request = (FullHttpRequest) msg;

    // 如果HTTP解码失败,返回HHTP异常
    if (!request.decoderResult().isSuccess() || (!"websocket".equals(request.headers().get("Upgrade")))) {
      sendHttpResponse(ctx, request, new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST));
      return;
    }

    // 正常WebSocket的Http连接请求,构造握手响应返回
    WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(
            "ws://" + request.headers().get(HttpHeaderNames.HOST), null, false);
    WebSocketServerHandshaker handshaker = wsFactory.newHandshaker(request);
    if (handshaker == null) { // 无法处理的websocket版本
      WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());
    } else { // 向客户端发送websocket握手,完成握手
      handshaker.handshake(ctx.channel(), request);
    }
  }

  /**
   * Http返回
   *
   * @param ctx
   * @param request
   * @param response
   */
  public static void sendHttpResponse(ChannelHandlerContext ctx, FullHttpRequest request, FullHttpResponse response) {
    // 返回应答给客户端
    if (response.status().code() != 200) {
      ByteBuf buf = Unpooled.copiedBuffer(response.status().toString(), CharsetUtil.UTF_8);
      response.content().writeBytes(buf);
      buf.release();
      HttpUtil.setContentLength(response, response.content().readableBytes());
    }

    // 如果是非Keep-Alive,关闭连接
    ChannelFuture f = ctx.channel().writeAndFlush(response);
    if (!HttpUtil.isKeepAlive(request) || response.status().code() != 200) {
      f.addListener(ChannelFutureListener.CLOSE);
    }
  }

  /**
   * 处理WebSocket中的WebSocket消息
   *
   * @param ctx 上下文
   * @param msg 消息
   */
  private void handleWebSocketMessage(ChannelHandlerContext ctx, Object msg) {
    //    ByteBuf content = ((WebSocketFrame) msg).content();
    WebSocketFrame frame = (WebSocketFrame) msg;
    if (frame instanceof TextWebSocketFrame) {
      TextWebSocketFrame textFrame = (TextWebSocketFrame) frame;
      System.out.println("服务器:接收到你的TextWebSocketFrame消息,内容是 " + textFrame.text());

      // 返回消息给客户端
      ctx.writeAndFlush(new TextWebSocketFrame("我是服务器,我是服务器"));

    } else if (frame instanceof BinaryWebSocketFrame) {
      System.out.println("服务器:接收到你的BinaryWebSocketFrame消息,内容是 ");
      ByteBuf content = frame.content();
      byte[] result = new byte[content.readableBytes()];
      content.readBytes(result);
      for (byte b : result) {
        System.out.print(b);
        System.out.print(",");
      }
      System.out.println();
      ctx.writeAndFlush(new BinaryWebSocketFrame(Unpooled.copiedBuffer(result)));
    }

  }

  @Override
  public void channelActive(ChannelHandlerContext ctx) {
    System.out.println("服务器:连接建立");
  }

  @Override
  public void channelInactive(ChannelHandlerContext ctx) {
    System.out.println("服务器:断开连接");
  }

  @Override
  public void exceptionCaught(ChannelHandlerContext ctx, Throwable throwable) {
    System.out.println("服务器:异常发送");
    throwable.printStackTrace();
  }

}

客户端

EasyWsClient

/*
 * Copyright (C), 2015-2018
 * FileName: EasyWsClient
 * Author:   zhao
 * Date:     2018/8/14 10:23
 * Description: 最简单的websocket客户端
 * History:
 * <author>          <time>          <version>          <desc>
 * 作者姓名           修改时间           版本号              描述
 */
package com.lizhaoblog.demopro.websocket.client;

import java.net.URI;
import java.net.URISyntaxException;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.DefaultHttpHeaders;
import io.netty.handler.codec.http.HttpClientCodec;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker;
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshakerFactory;
import io.netty.handler.codec.http.websocketx.WebSocketVersion;

/**
 * 〈一句话功能简述〉<br>
 * 〈最简单的websocket客户端〉
 *
 * @author zhao
 * @date 2018/8/14 10:23
 * @since 1.0.1
 */
public class EasyWsClient {
  private static EventLoopGroup group = new NioEventLoopGroup();
  //  private static final String ip = "127.0.0.1";
  //  private static final int port = 8088;

  private String ip;
  private int port;
  private String uriStr;
  private static EasyWsClientHandler handler;

  public EasyWsClient(String ip, int port) {
    this.ip = ip;
    this.port = port;
    uriStr = "ws//" + ip + ":" + port;
  }

  public void run() throws InterruptedException, URISyntaxException {
    // 主要是为handler(自己写的类)服务,用于初始化EasyWsHandle
    URI wsUri = new URI(uriStr);
    WebSocketClientHandshaker webSocketClientHandshaker = WebSocketClientHandshakerFactory
            .newHandshaker(wsUri, WebSocketVersion.V13, null, true, new DefaultHttpHeaders(), 100 * 1024 * 1024);
    handler = new EasyWsClientHandler(webSocketClientHandshaker);

    // 设置Bootstrap
    Bootstrap bootstrap = new Bootstrap();
    bootstrap.group(group);
    bootstrap.channel(NioSocketChannel.class);

    bootstrap.handler(new ChannelInitializer() {
      @Override
      protected void initChannel(Channel ch) {
        ChannelPipeline pipeline = ch.pipeline();
        pipeline.addLast(new HttpClientCodec());
        pipeline.addLast(new HttpObjectAggregator(65536));
        pipeline.addLast(handler);
      }
    });

    // 连接服务端
    ChannelFuture channelFuture = bootstrap.connect(ip, port).sync();
    handler.handshakeFuture().sync();

    // 传输文本
    TextWebSocketFrame frame = new TextWebSocketFrame("hello");
    channelFuture.channel().writeAndFlush(frame);
    // 传输二进制字节数据
    byte[] bytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    BinaryWebSocketFrame byteFrame = new BinaryWebSocketFrame(Unpooled.copiedBuffer(bytes));
    channelFuture.channel().writeAndFlush(byteFrame);

    // 堵塞线程,保持长连接
    channelFuture.channel().closeFuture().sync();
  }

}

EasyWsClientHandler

/*
 * Copyright (C), 2015-2018
 * FileName: EasyWsClientHandler
 * Author:   zhao
 * Date:     2018/8/14 10:23
 * Description: 最简单的WebSocket的handle
 * History:
 * <author>          <time>          <version>          <desc>
 * 作者姓名           修改时间           版本号              描述
 */
package com.lizhaoblog.demopro.websocket.client;

import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
import io.netty.handler.codec.http.websocketx.PongWebSocketFrame;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import io.netty.util.CharsetUtil;

/**
 * 〈一句话功能简述〉<br>
 * 〈最简单的WebSocket的handle〉
 *
 * @author zhao
 * @date 2018/8/14 10:23
 * @since 1.0.1
 */
public class EasyWsClientHandler extends SimpleChannelInboundHandler<Object> {
  private final WebSocketClientHandshaker handshaker;
  private ChannelPromise handshakeFuture;

  public EasyWsClientHandler(WebSocketClientHandshaker handshaker) {
    this.handshaker = handshaker;
  }

  public ChannelFuture handshakeFuture() {
    return handshakeFuture;
  }

  @Override
  public void handlerAdded(ChannelHandlerContext ctx) {
    handshakeFuture = ctx.newPromise();
  }

  @Override
  public void channelActive(ChannelHandlerContext ctx) throws Exception {
    System.out.println("客户端连接建立");
    // 在通道连接成功后发送握手连接
    handshaker.handshake(ctx.channel());
    super.channelActive(ctx);
  }

  @Override
  protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
    Channel ch = ctx.channel();

    // 这里是第一次使用http连接成功的时候
    if (!handshaker.isHandshakeComplete()) {
      handshaker.finishHandshake(ch, (FullHttpResponse) msg);
      System.out.println("WebSocket Client connected!");
      handshakeFuture.setSuccess();
      return;
    }

    // 这里是第一次使用http连接失败的时候
    if (msg instanceof FullHttpResponse) {
      FullHttpResponse response = (FullHttpResponse) msg;
      throw new IllegalStateException(
              "Unexpected FullHttpResponse (getStatus=" + response.getStatus() + ", content=" + response.content()
                      .toString(CharsetUtil.UTF_8) + ')');
    }

    // 这里是服务器与客户端进行通讯的
    WebSocketFrame frame = (WebSocketFrame) msg;
    if (frame instanceof TextWebSocketFrame) {
      TextWebSocketFrame textFrame = (TextWebSocketFrame) frame;
      System.out.println("客户端:接收到TextWebSocketFrame消息,消息内容是-- " + textFrame.text());
    } else if (frame instanceof BinaryWebSocketFrame) {
      System.out.println("客户端:接收到BinaryWebSocketFrame消息,消息内容是-- ");
      ByteBuf content = frame.content();
      byte[] result = new byte[content.readableBytes()];
      content.readBytes(result);
      for (byte b : result) {
        System.out.print(b);
        System.out.print(",");
      }
      System.out.println();
    } else if (frame instanceof PongWebSocketFrame) {
      System.out.println("WebSocket Client received pong");
    } else if (frame instanceof CloseWebSocketFrame) {
      System.out.println("WebSocket Client received closing");
      ch.close();
    }

  }

  @Override
  public void exceptionCaught(ChannelHandlerContext ctx, Throwable arg1) {
    System.out.println("异常发生");
    arg1.printStackTrace();
  }

  @Override
  public void channelInactive(ChannelHandlerContext ctx) throws Exception {
    System.out.println("客户端连接断开");
    super.channelInactive(ctx);
  }
}

测试类

EasyWsTest

/*
 * Copyright (C), 2015-2018
 * FileName: EasyWsTest
 * Author:   zhao
 * Date:     2018/8/14 11:08
 * Description: EasyWs的测试类
 * History:
 * <author>          <time>          <version>          <desc>
 * 作者姓名           修改时间           版本号              描述
 */
package com.lizhaoblog.demopro.websocket;

import com.lizhaoblog.demopro.websocket.client.EasyWsClient;
import com.lizhaoblog.demopro.websocket.server.EasyWsServer;

import org.junit.Test;

/**
 * 〈一句话功能简述〉<br>
 * 〈EasyWs的测试类〉
 *
 * @author zhao
 * @date 2018/8/14 11:08
 * @since 1.0.1
 */
public class EasyWsTest {
    

  private static final String IP = "127.0.0.1";
  private static final int PORT = 8088;

  @Test
  public void startServer() throws Exception {
    EasyWsServer easyWsServer = new EasyWsServer(PORT);
    easyWsServer.start();
  }

  @Test
  public void startClient() throws Exception {
    EasyWsClient easyWsClient = new EasyWsClient(IP, PORT);
    easyWsClient.run();
  }
}

测试

  1. 打开EasyWsTest,运行startServer
  2. 打开EasyWsTest,运行startClient
  3. 查看结果
    • 服务端:连接建立–服务器收到http握手消息–服务器收到消息(文本)–服务器收到字节消息
    • 服务端
Connected to the target VM, address: '127.0.0.1:3215', transport: 'socket'
2018-08-14 11:55:39.087 DEBUG io.netty.util.internal.logging.InternalLoggerFactory - Using SLF4J as the default logging framework
2018-08-14 11:55:39.099 DEBUG io.netty.channel.MultithreadEventLoopGroup - -Dio.netty.eventLoopThreads: 16
2018-08-14 11:55:39.122 DEBUG io.netty.util.internal.PlatformDependent0 - java.nio.Buffer.address: available
2018-08-14 11:55:39.123 DEBUG io.netty.util.internal.PlatformDependent0 - sun.misc.Unsafe.theUnsafe: available
2018-08-14 11:55:39.123 DEBUG io.netty.util.internal.PlatformDependent0 - sun.misc.Unsafe.copyMemory: available
2018-08-14 11:55:39.124 DEBUG io.netty.util.internal.PlatformDependent0 - direct buffer constructor: available
2018-08-14 11:55:39.125 DEBUG io.netty.util.internal.PlatformDependent0 - java.nio.Bits.unaligned: available, true
2018-08-14 11:55:39.125 DEBUG io.netty.util.internal.PlatformDependent0 - java.nio.DirectByteBuffer.<init>(long, int): available
2018-08-14 11:55:39.126 DEBUG io.netty.util.internal.Cleaner0 - java.nio.ByteBuffer.cleaner(): available
2018-08-14 11:55:39.126 DEBUG io.netty.util.internal.PlatformDependent - Platform: Windows
2018-08-14 11:55:39.127 DEBUG io.netty.util.internal.PlatformDependent - Java version: 8
2018-08-14 11:55:39.127 DEBUG io.netty.util.internal.PlatformDependent - -Dio.netty.noUnsafe: false
2018-08-14 11:55:39.127 DEBUG io.netty.util.internal.PlatformDependent - sun.misc.Unsafe: available
2018-08-14 11:55:39.127 DEBUG io.netty.util.internal.PlatformDependent - -Dio.netty.noJavassist: false
2018-08-14 11:55:39.128 DEBUG io.netty.util.internal.PlatformDependent - Javassist: unavailable
2018-08-14 11:55:39.128 DEBUG io.netty.util.internal.PlatformDependent - You don't have Javassist in your class path or you don't have enough permission to load dynamically generated classes.  Please check the configuration for better performance.
2018-08-14 11:55:39.129 DEBUG io.netty.util.internal.PlatformDependent - -Dio.netty.tmpdir: C:\Users\ADMINI~1\AppData\Local\Temp (java.io.tmpdir)
2018-08-14 11:55:39.129 DEBUG io.netty.util.internal.PlatformDependent - -Dio.netty.bitMode: 64 (sun.arch.data.model)
2018-08-14 11:55:39.129 DEBUG io.netty.util.internal.PlatformDependent - -Dio.netty.noPreferDirect: false
2018-08-14 11:55:39.129 DEBUG io.netty.util.internal.PlatformDependent - io.netty.maxDirectMemory: 3806855168 bytes
2018-08-14 11:55:39.183 DEBUG io.netty.channel.nio.NioEventLoop - -Dio.netty.noKeySetOptimization: false
2018-08-14 11:55:39.184 DEBUG io.netty.channel.nio.NioEventLoop - -Dio.netty.selectorAutoRebuildThreshold: 512
2018-08-14 11:55:39.186 DEBUG io.netty.util.internal.PlatformDependent - org.jctools-core.MpscChunkedArrayQueue: available
2018-08-14 11:55:39.380 DEBUG io.netty.channel.DefaultChannelId - -Dio.netty.processId: 6492 (auto-detected)
2018-08-14 11:55:39.382 DEBUG io.netty.util.NetUtil - -Djava.net.preferIPv4Stack: false
2018-08-14 11:55:39.383 DEBUG io.netty.util.NetUtil - -Djava.net.preferIPv6Addresses: false
2018-08-14 11:55:39.411 DEBUG io.netty.util.NetUtil - Loopback interface: lo (Software Loopback Interface 1, 127.0.0.1)
2018-08-14 11:55:39.412 DEBUG io.netty.util.NetUtil - \proc\sys\net\core\somaxconn: 200 (non-existent)
2018-08-14 11:55:39.444 DEBUG io.netty.channel.DefaultChannelId - -Dio.netty.machineId: 94:de:80:ff:fe:78:f9:54 (auto-detected)
2018-08-14 11:55:39.447 DEBUG io.netty.util.internal.ThreadLocalRandom - -Dio.netty.initialSeedUniquifier: 0x912cf1a5dfc99b85
2018-08-14 11:55:39.466 DEBUG io.netty.util.ResourceLeakDetector - -Dio.netty.leakDetection.level: simple
2018-08-14 11:55:39.467 DEBUG io.netty.util.ResourceLeakDetector - -Dio.netty.leakDetection.maxRecords: 4
2018-08-14 11:55:39.497 DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.numHeapArenas: 16
2018-08-14 11:55:39.497 DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.numDirectArenas: 16
2018-08-14 11:55:39.498 DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.pageSize: 8192
2018-08-14 11:55:39.498 DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.maxOrder: 11
2018-08-14 11:55:39.498 DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.chunkSize: 16777216
2018-08-14 11:55:39.498 DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.tinyCacheSize: 512
2018-08-14 11:55:39.498 DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.smallCacheSize: 256
2018-08-14 11:55:39.498 DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.normalCacheSize: 64
2018-08-14 11:55:39.498 DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.maxCachedBufferCapacity: 32768
2018-08-14 11:55:39.498 DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.cacheTrimInterval: 8192
2018-08-14 11:55:39.512 DEBUG io.netty.buffer.ByteBufUtil - -Dio.netty.allocator.type: pooled
2018-08-14 11:55:39.513 DEBUG io.netty.buffer.ByteBufUtil - -Dio.netty.threadLocalDirectBufferSize: 65536
2018-08-14 11:55:39.513 DEBUG io.netty.buffer.ByteBufUtil - -Dio.netty.maxThreadLocalCharBufferSize: 16384
2018-08-14 11:55:42.719 DEBUG io.netty.buffer.AbstractByteBuf - -Dio.netty.buffer.bytebuf.checkAccessible: true
2018-08-14 11:55:42.724 DEBUG io.netty.util.ResourceLeakDetectorFactory - Loaded default ResourceLeakDetector: io.netty.util.ResourceLeakDetector@42e2b085
服务器:连接建立
2018-08-14 11:55:42.788 DEBUG io.netty.util.Recycler - -Dio.netty.recycler.maxCapacityPerThread: 32768
2018-08-14 11:55:42.788 DEBUG io.netty.util.Recycler - -Dio.netty.recycler.maxSharedCapacityFactor: 2
2018-08-14 11:55:42.788 DEBUG io.netty.util.Recycler - -Dio.netty.recycler.linkCapacity: 16
2018-08-14 11:55:42.788 DEBUG io.netty.util.Recycler - -Dio.netty.recycler.ratio: 8
2018-08-14 11:55:42.836 DEBUG io.netty.handler.codec.http.websocketx.WebSocketServerHandshaker - [id: 0x08778b2d, L:/127.0.0.1:8088 - R:/127.0.0.1:3327] WebSocket version V13 server handshake
2018-08-14 11:55:42.842 DEBUG io.netty.handler.codec.http.websocketx.WebSocketServerHandshaker - WebSocket version 13 server handshake key: YR/wvrnrJz9kEkn6LSuFug==, response: 6XulC19MJ2P54cdvYMhyy/OHqNU=
2018-08-14 11:55:42.871 DEBUG io.netty.handler.codec.http.websocketx.WebSocket08FrameDecoder - Decoding WebSocket Frame opCode=1
2018-08-14 11:55:42.871 DEBUG io.netty.handler.codec.http.websocketx.WebSocket08FrameDecoder - Decoding WebSocket Frame length=5
服务器:接收到你的TextWebSocketFrame消息,内容是 hello
2018-08-14 11:55:42.873 DEBUG io.netty.handler.codec.http.websocketx.WebSocket08FrameEncoder - Encoding WebSocket Frame opCode=1 length=33
2018-08-14 11:55:42.874 DEBUG io.netty.handler.codec.http.websocketx.WebSocket08FrameDecoder - Decoding WebSocket Frame opCode=2
2018-08-14 11:55:42.874 DEBUG io.netty.handler.codec.http.websocketx.WebSocket08FrameDecoder - Decoding WebSocket Frame length=9
服务器:接收到你的BinaryWebSocketFrame消息,内容是 
1,2,3,4,5,6,7,8,9,
2018-08-14 11:55:42.879 DEBUG io.netty.handler.codec.http.websocketx.WebSocket08FrameEncoder - Encoding WebSocket Frame opCode=2 length=9
Disconnected from the target VM, address: '127.0.0.1:3215', transport: 'socket'

Process finished with exit code -1
- 客户端
2018-08-14 11:55:42.240 DEBUG io.netty.util.internal.logging.InternalLoggerFactory - Using SLF4J as the default logging framework
2018-08-14 11:55:42.246 DEBUG io.netty.channel.MultithreadEventLoopGroup - -Dio.netty.eventLoopThreads: 16
2018-08-14 11:55:42.271 DEBUG io.netty.util.internal.PlatformDependent0 - java.nio.Buffer.address: available
2018-08-14 11:55:42.272 DEBUG io.netty.util.internal.PlatformDependent0 - sun.misc.Unsafe.theUnsafe: available
2018-08-14 11:55:42.272 DEBUG io.netty.util.internal.PlatformDependent0 - sun.misc.Unsafe.copyMemory: available
2018-08-14 11:55:42.273 DEBUG io.netty.util.internal.PlatformDependent0 - direct buffer constructor: available
2018-08-14 11:55:42.274 DEBUG io.netty.util.internal.PlatformDependent0 - java.nio.Bits.unaligned: available, true
2018-08-14 11:55:42.274 DEBUG io.netty.util.internal.PlatformDependent0 - java.nio.DirectByteBuffer.<init>(long, int): available
2018-08-14 11:55:42.275 DEBUG io.netty.util.internal.Cleaner0 - java.nio.ByteBuffer.cleaner(): available
2018-08-14 11:55:42.276 DEBUG io.netty.util.internal.PlatformDependent - Platform: Windows
2018-08-14 11:55:42.277 DEBUG io.netty.util.internal.PlatformDependent - Java version: 8
2018-08-14 11:55:42.277 DEBUG io.netty.util.internal.PlatformDependent - -Dio.netty.noUnsafe: false
2018-08-14 11:55:42.277 DEBUG io.netty.util.internal.PlatformDependent - sun.misc.Unsafe: available
2018-08-14 11:55:42.277 DEBUG io.netty.util.internal.PlatformDependent - -Dio.netty.noJavassist: false
2018-08-14 11:55:42.278 DEBUG io.netty.util.internal.PlatformDependent - Javassist: unavailable
2018-08-14 11:55:42.279 DEBUG io.netty.util.internal.PlatformDependent - You don't have Javassist in your class path or you don't have enough permission to load dynamically generated classes.  Please check the configuration for better performance.
2018-08-14 11:55:42.279 DEBUG io.netty.util.internal.PlatformDependent - -Dio.netty.tmpdir: C:\Users\ADMINI~1\AppData\Local\Temp (java.io.tmpdir)
2018-08-14 11:55:42.279 DEBUG io.netty.util.internal.PlatformDependent - -Dio.netty.bitMode: 64 (sun.arch.data.model)
2018-08-14 11:55:42.282 DEBUG io.netty.util.internal.PlatformDependent - -Dio.netty.noPreferDirect: false
2018-08-14 11:55:42.282 DEBUG io.netty.util.internal.PlatformDependent - io.netty.maxDirectMemory: 3806855168 bytes
2018-08-14 11:55:42.301 DEBUG io.netty.channel.nio.NioEventLoop - -Dio.netty.noKeySetOptimization: false
2018-08-14 11:55:42.301 DEBUG io.netty.channel.nio.NioEventLoop - -Dio.netty.selectorAutoRebuildThreshold: 512
2018-08-14 11:55:42.303 DEBUG io.netty.util.internal.PlatformDependent - org.jctools-core.MpscChunkedArrayQueue: available
2018-08-14 11:55:42.488 DEBUG io.netty.channel.DefaultChannelId - -Dio.netty.processId: 18412 (auto-detected)
2018-08-14 11:55:42.490 DEBUG io.netty.util.NetUtil - -Djava.net.preferIPv4Stack: false
2018-08-14 11:55:42.491 DEBUG io.netty.util.NetUtil - -Djava.net.preferIPv6Addresses: false
2018-08-14 11:55:42.516 DEBUG io.netty.util.NetUtil - Loopback interface: lo (Software Loopback Interface 1, 127.0.0.1)
2018-08-14 11:55:42.518 DEBUG io.netty.util.NetUtil - \proc\sys\net\core\somaxconn: 200 (non-existent)
2018-08-14 11:55:42.545 DEBUG io.netty.channel.DefaultChannelId - -Dio.netty.machineId: 94:de:80:ff:fe:78:f9:54 (auto-detected)
2018-08-14 11:55:42.546 DEBUG io.netty.util.internal.ThreadLocalRandom - -Dio.netty.initialSeedUniquifier: 0x30542ca8d536a1bd
2018-08-14 11:55:42.561 DEBUG io.netty.util.ResourceLeakDetector - -Dio.netty.leakDetection.level: simple
2018-08-14 11:55:42.561 DEBUG io.netty.util.ResourceLeakDetector - -Dio.netty.leakDetection.maxRecords: 4
2018-08-14 11:55:42.590 DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.numHeapArenas: 16
2018-08-14 11:55:42.591 DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.numDirectArenas: 16
2018-08-14 11:55:42.591 DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.pageSize: 8192
2018-08-14 11:55:42.591 DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.maxOrder: 11
2018-08-14 11:55:42.591 DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.chunkSize: 16777216
2018-08-14 11:55:42.591 DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.tinyCacheSize: 512
2018-08-14 11:55:42.591 DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.smallCacheSize: 256
2018-08-14 11:55:42.592 DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.normalCacheSize: 64
2018-08-14 11:55:42.592 DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.maxCachedBufferCapacity: 32768
2018-08-14 11:55:42.592 DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.cacheTrimInterval: 8192
2018-08-14 11:55:42.606 DEBUG io.netty.buffer.ByteBufUtil - -Dio.netty.allocator.type: pooled
2018-08-14 11:55:42.606 DEBUG io.netty.buffer.ByteBufUtil - -Dio.netty.threadLocalDirectBufferSize: 65536
2018-08-14 11:55:42.606 DEBUG io.netty.buffer.ByteBufUtil - -Dio.netty.maxThreadLocalCharBufferSize: 16384
2018-08-14 11:55:42.645 DEBUG io.netty.buffer.AbstractByteBuf - -Dio.netty.buffer.bytebuf.checkAccessible: true
2018-08-14 11:55:42.648 DEBUG io.netty.util.ResourceLeakDetectorFactory - Loaded default ResourceLeakDetector: io.netty.util.ResourceLeakDetector@3724974
客户端连接建立
2018-08-14 11:55:42.681 DEBUG io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker13 - WebSocket version 13 client handshake key: YR/wvrnrJz9kEkn6LSuFug==, expected response: 6XulC19MJ2P54cdvYMhyy/OHqNU=
2018-08-14 11:55:42.690 DEBUG io.netty.util.Recycler - -Dio.netty.recycler.maxCapacityPerThread: 32768
2018-08-14 11:55:42.690 DEBUG io.netty.util.Recycler - -Dio.netty.recycler.maxSharedCapacityFactor: 2
2018-08-14 11:55:42.690 DEBUG io.netty.util.Recycler - -Dio.netty.recycler.linkCapacity: 16
2018-08-14 11:55:42.690 DEBUG io.netty.util.Recycler - -Dio.netty.recycler.ratio: 8
WebSocket Client connected!
2018-08-14 11:55:42.869 DEBUG io.netty.handler.codec.http.websocketx.WebSocket08FrameEncoder - Encoding WebSocket Frame opCode=1 length=5
2018-08-14 11:55:42.872 DEBUG io.netty.handler.codec.http.websocketx.WebSocket08FrameEncoder - Encoding WebSocket Frame opCode=2 length=9
2018-08-14 11:55:42.875 DEBUG io.netty.handler.codec.http.websocketx.WebSocket08FrameDecoder - Decoding WebSocket Frame opCode=1
2018-08-14 11:55:42.875 DEBUG io.netty.handler.codec.http.websocketx.WebSocket08FrameDecoder - Decoding WebSocket Frame length=33
客户端:接收到TextWebSocketFrame消息,消息内容是-- 我是服务器,我是服务器
2018-08-14 11:55:42.879 DEBUG io.netty.handler.codec.http.websocketx.WebSocket08FrameDecoder - Decoding WebSocket Frame opCode=2
2018-08-14 11:55:42.880 DEBUG io.netty.handler.codec.http.websocketx.WebSocket08FrameDecoder - Decoding WebSocket Frame length=9
客户端:接收到BinaryWebSocketFrame消息,消息内容是-- 
1,2,3,4,5,6,7,8,9,

上面的代码在码云上 https://gitee.com/lizhaoandroid/JgServer
的test下的com.lizhaoblog.demopro.websocket包目录下,可以下载查看

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/cmqwan/article/details/81673267

智能推荐

攻防世界_难度8_happy_puzzle_攻防世界困难模式攻略图文-程序员宅基地

文章浏览阅读645次。这个肯定是末尾的IDAT了,因为IDAT必须要满了才会开始一下个IDAT,这个明显就是末尾的IDAT了。,对应下面的create_head()代码。,对应下面的create_tail()代码。不要考虑爆破,我已经试了一下,太多情况了。题目来源:UNCTF。_攻防世界困难模式攻略图文

达梦数据库的导出(备份)、导入_达梦数据库导入导出-程序员宅基地

文章浏览阅读2.9k次,点赞3次,收藏10次。偶尔会用到,记录、分享。1. 数据库导出1.1 切换到dmdba用户su - dmdba1.2 进入达梦数据库安装路径的bin目录,执行导库操作  导出语句:./dexp cwy_init/[email protected]:5236 file=cwy_init.dmp log=cwy_init_exp.log 注释:   cwy_init/init_123..._达梦数据库导入导出

js引入kindeditor富文本编辑器的使用_kindeditor.js-程序员宅基地

文章浏览阅读1.9k次。1. 在官网上下载KindEditor文件,可以删掉不需要要到的jsp,asp,asp.net和php文件夹。接着把文件夹放到项目文件目录下。2. 修改html文件,在页面引入js文件:<script type="text/javascript" src="./kindeditor/kindeditor-all.js"></script><script type="text/javascript" src="./kindeditor/lang/zh-CN.js"_kindeditor.js

STM32学习过程记录11——基于STM32G431CBU6硬件SPI+DMA的高效WS2812B控制方法-程序员宅基地

文章浏览阅读2.3k次,点赞6次,收藏14次。SPI的详情简介不必赘述。假设我们通过SPI发送0xAA,我们的数据线就会变为10101010,通过修改不同的内容,即可修改SPI中0和1的持续时间。比如0xF0即为前半周期为高电平,后半周期为低电平的状态。在SPI的通信模式中,CPHA配置会影响该实验,下图展示了不同采样位置的SPI时序图[1]。CPOL = 0,CPHA = 1:CLK空闲状态 = 低电平,数据在下降沿采样,并在上升沿移出CPOL = 0,CPHA = 0:CLK空闲状态 = 低电平,数据在上升沿采样,并在下降沿移出。_stm32g431cbu6

计算机网络-数据链路层_接收方收到链路层数据后,使用crc检验后,余数为0,说明链路层的传输时可靠传输-程序员宅基地

文章浏览阅读1.2k次,点赞2次,收藏8次。数据链路层习题自测问题1.数据链路(即逻辑链路)与链路(即物理链路)有何区别?“电路接通了”与”数据链路接通了”的区别何在?2.数据链路层中的链路控制包括哪些功能?试讨论数据链路层做成可靠的链路层有哪些优点和缺点。3.网络适配器的作用是什么?网络适配器工作在哪一层?4.数据链路层的三个基本问题(帧定界、透明传输和差错检测)为什么都必须加以解决?5.如果在数据链路层不进行帧定界,会发生什么问题?6.PPP协议的主要特点是什么?为什么PPP不使用帧的编号?PPP适用于什么情况?为什么PPP协议不_接收方收到链路层数据后,使用crc检验后,余数为0,说明链路层的传输时可靠传输

软件测试工程师移民加拿大_无证移民,未受过软件工程师的教育(第1部分)-程序员宅基地

文章浏览阅读587次。软件测试工程师移民加拿大 无证移民,未受过软件工程师的教育(第1部分) (Undocumented Immigrant With No Education to Software Engineer(Part 1))Before I start, I want you to please bear with me on the way I write, I have very little gen...

随便推点

Thinkpad X250 secure boot failed 启动失败问题解决_安装完系统提示secureboot failure-程序员宅基地

文章浏览阅读304次。Thinkpad X250笔记本电脑,装的是FreeBSD,进入BIOS修改虚拟化配置(其后可能是误设置了安全开机),保存退出后系统无法启动,显示:secure boot failed ,把自己惊出一身冷汗,因为这台笔记本刚好还没开始做备份.....根据错误提示,到bios里面去找相关配置,在Security里面找到了Secure Boot选项,发现果然被设置为Enabled,将其修改为Disabled ,再开机,终于正常启动了。_安装完系统提示secureboot failure

C++如何做字符串分割(5种方法)_c++ 字符串分割-程序员宅基地

文章浏览阅读10w+次,点赞93次,收藏352次。1、用strtok函数进行字符串分割原型: char *strtok(char *str, const char *delim);功能:分解字符串为一组字符串。参数说明:str为要分解的字符串,delim为分隔符字符串。返回值:从str开头开始的一个个被分割的串。当没有被分割的串时则返回NULL。其它:strtok函数线程不安全,可以使用strtok_r替代。示例://借助strtok实现split#include <string.h>#include <stdio.h&_c++ 字符串分割

2013第四届蓝桥杯 C/C++本科A组 真题答案解析_2013年第四届c a组蓝桥杯省赛真题解答-程序员宅基地

文章浏览阅读2.3k次。1 .高斯日记 大数学家高斯有个好习惯:无论如何都要记日记。他的日记有个与众不同的地方,他从不注明年月日,而是用一个整数代替,比如:4210后来人们知道,那个整数就是日期,它表示那一天是高斯出生后的第几天。这或许也是个好习惯,它时时刻刻提醒着主人:日子又过去一天,还有多少时光可以用于浪费呢?高斯出生于:1777年4月30日。在高斯发现的一个重要定理的日记_2013年第四届c a组蓝桥杯省赛真题解答

基于供需算法优化的核极限学习机(KELM)分类算法-程序员宅基地

文章浏览阅读851次,点赞17次,收藏22次。摘要:本文利用供需算法对核极限学习机(KELM)进行优化,并用于分类。

metasploitable2渗透测试_metasploitable2怎么进入-程序员宅基地

文章浏览阅读1.1k次。一、系统弱密码登录1、在kali上执行命令行telnet 192.168.26.1292、Login和password都输入msfadmin3、登录成功,进入系统4、测试如下:二、MySQL弱密码登录:1、在kali上执行mysql –h 192.168.26.129 –u root2、登录成功,进入MySQL系统3、测试效果:三、PostgreSQL弱密码登录1、在Kali上执行psql -h 192.168.26.129 –U post..._metasploitable2怎么进入

Python学习之路:从入门到精通的指南_python人工智能开发从入门到精通pdf-程序员宅基地

文章浏览阅读257次。本文将为初学者提供Python学习的详细指南,从Python的历史、基础语法和数据类型到面向对象编程、模块和库的使用。通过本文,您将能够掌握Python编程的核心概念,为今后的编程学习和实践打下坚实基础。_python人工智能开发从入门到精通pdf

推荐文章

热门文章

相关标签