精华内容
下载资源
问答
  • 搭建tcp服务器: import io.netty.bootstrap.ServerBootstrap; import io.netty.buffer.Unpooled; import io.netty.channel.*; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket....

     搭建tcp服务器:

    import io.netty.bootstrap.ServerBootstrap;
    import io.netty.buffer.Unpooled;
    import io.netty.channel.*;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.SocketChannel;
    import io.netty.channel.socket.nio.NioServerSocketChannel;
    
    import java.net.InetSocketAddress;
    
    /**
     * User: linxz
     * Date: 2019-12-04 16:10
     **/
    public class NettyServer{
        
        public NettyServer(int port){
            NioEventLoopGroup boosGroup = null;
            NioEventLoopGroup workGroup = null;
            try {
                System.out.println("开始创建netty TCP服务");
                boosGroup=new NioEventLoopGroup();
                workGroup=new NioEventLoopGroup();
                ServerBootstrap serverBootstrap = new ServerBootstrap();
                serverBootstrap.group(boosGroup,workGroup);
                //系统用于临时存放已完成三次握手的请求的队列的最大长度,如果连接建立频繁,服务器处理创建新连接较慢,可以适当调大这个参数
                serverBootstrap.option(ChannelOption.SO_BACKLOG,1024);
                serverBootstrap.channel(NioServerSocketChannel.class);
                //一定要用这种方式设置handler,否则客户端一旦关闭连接之后就连接不上来
                serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        socketChannel.pipeline().addLast(new MsgHandler());
                    }
                });
                Channel serverChannel = serverBootstrap.bind(port).sync().channel();
                System.out.println("netty TCP服务启动成功,端口:" + port);
                serverChannel.closeFuture().sync();
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                if(workGroup!=null){
                    workGroup.shutdownGracefully();
                }
                if(boosGroup!=null){
                    boosGroup.shutdownGracefully();
                }
                System.out.println("程序异常结束");
            }
        }
    
        class MsgHandler extends ChannelInboundHandlerAdapter {
            @Override
            public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
                Channel channel=ctx.channel();
                InetSocketAddress address = (InetSocketAddress)channel.remoteAddress();
                String ip=address.getAddress().getHostAddress();
                int port=address.getPort();
                System.out.println("有client加入-"+ip+":"+port);
            }
    
            @Override
            public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
                Channel channel=ctx.channel();
                InetSocketAddress address = (InetSocketAddress)channel.remoteAddress();
                String ip=address.getAddress().getHostAddress();
                int port=address.getPort();
                System.out.println("有client断开连接-"+ip+":"+port);
            }
    
            @Override
            public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                System.out.println("接收到了数据");
                System.out.println("接收到的数据对象类型:"+msg.getClass());
            }
    
            @Override
            public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
                ctx.writeAndFlush(Unpooled.EMPTY_BUFFER);//.addListener(ChannelFutureListener.CLOSE);
            }
    
            @Override
            public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
                System.out.println("触发exceptionCaught");
                cause.printStackTrace();
                ctx.close();
            }
        }
    }
    
    

    搭建websocket服务器:

    import io.netty.bootstrap.ServerBootstrap;
    import io.netty.channel.*;
    import io.netty.channel.group.ChannelGroup;
    import io.netty.channel.group.DefaultChannelGroup;
    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.codec.http.websocketx.TextWebSocketFrame;
    import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
    import io.netty.handler.stream.ChunkedWriteHandler;
    import io.netty.util.concurrent.ImmediateEventExecutor;
    
    import java.net.InetSocketAddress;
    
    /**
     * User: linxz
     * Date: 2019-12-04 16:14
     **/
    public class WebSocketServer {
    
        //所有的websocket连接
        private static final ChannelGroup channelGroup = new DefaultChannelGroup(ImmediateEventExecutor.INSTANCE);
    
        /**
         * 给客户端发送消息
         */
        public static final void sendMsg(String msg){
            if(channelGroup.isEmpty()){
                System.out.println("暂无客户端连接!");
                return ;
            }
            channelGroup.writeAndFlush(new TextWebSocketFrame(msg));
        }
    
        public WebSocketServer(int port){
            NioEventLoopGroup boosGroup = null;
            NioEventLoopGroup workGroup = null;
            try {
                System.out.println("开始创建netty websocket服务");
                boosGroup=new NioEventLoopGroup();
                workGroup=new NioEventLoopGroup();
                ServerBootstrap serverBootstrap = new ServerBootstrap();
                serverBootstrap.group(boosGroup,workGroup);
                //系统用于临时存放已完成三次握手的请求的队列的最大长度,如果连接建立频繁,服务器处理创建新连接较慢,可以适当调大这个参数
                serverBootstrap.option(ChannelOption.SO_BACKLOG,1024);
                serverBootstrap.channel(NioServerSocketChannel.class);
                //一定要用这种方式设置handler,否则客户端一旦关闭连接之后就连接不上来
                serverBootstrap.childHandler(new SocketChannelInitializer(channelGroup));
                Channel serverChannel = serverBootstrap.bind(port).sync().channel();
                System.out.println("netty websocket服务启动成功,端口:" + port);
                serverChannel.closeFuture().sync();
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                if(workGroup!=null){
                    workGroup.shutdownGracefully();
                }
                if(boosGroup!=null){
                    boosGroup.shutdownGracefully();
                }
                System.out.println("程序异常结束");
            }
        }
    }
    
    class SocketChannelInitializer extends ChannelInitializer<Channel> {
    
        private final ChannelGroup group;
    
        public SocketChannelInitializer(ChannelGroup group){
            this.group=group;
        }
    
        @Override
        protected void initChannel(Channel channel) throws Exception {
            ChannelPipeline pipeline = channel.pipeline();
            pipeline.addLast(new HttpServerCodec());
            pipeline.addLast(new HttpObjectAggregator(64 * 1024));
            pipeline.addLast(new ChunkedWriteHandler());
            pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));
            pipeline.addLast(new WebSocketHandler(group));
        }
    }
    
    class WebSocketHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
        private final ChannelGroup group;
    
        public WebSocketHandler(ChannelGroup group) {
            this.group=group;
        }
    
        @Override
        public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
            Channel channel=ctx.channel();
            InetSocketAddress address = (InetSocketAddress)channel.remoteAddress();
            String ip=address.getAddress().getHostAddress();
            int port=address.getPort();
            System.out.println("有连接加入,"+ip+":"+port);
            group.add(channel);
        }
    
        @Override
        protected void channelRead0(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame msg) throws Exception {
            System.out.println("收到客户端发送的消息:"+msg.text());
        }
    
    
    
        @Override
        public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
            Channel channel=ctx.channel();
            InetSocketAddress address = (InetSocketAddress)channel.remoteAddress();
            String ip=address.getAddress().getHostAddress();
            int port=address.getPort();
            System.out.println("有连接断开,"+ip+":"+port);
            group.remove(channel);
        }
    
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            System.out.println("websocket处理错误。");
            cause.printStackTrace();
            super.exceptionCaught(ctx, cause);
        }
    }

     

    展开全文
  • Netty 搭建 TCP服务器(一)

    千次阅读 2019-03-17 14:05:55
    需求 ipad点击弹出客户端相应操作,需要软件客户端在windows系统上自动弹出软件界面,前提是软件客户端在后台已经开启。 设计思路 ipad发送点击消息到websocket服务器,websocket...搭建tcp服务器采用netty,一是ne...

    本文内容如有错误、不足之处,欢迎技术爱好者们一同探讨,在本文下面讨论区留言,感谢。

    需求
    软件客户端定时发送心跳包到TCP服务器,TCP服务器在接到消息情况下(是与webSocket服信息交互),发送命令到软件客户端。

    设计思路
    流程图:
    通信逻辑流程图

    设计代码

    1. 项目介绍
      项目使用gradle构建、springboot框架。

    2. netty搭建
      搭建tcp服务器采用netty,一是netty是nio服务器,效率高。而是netty搭建比较成熟,可以找到资料进行业务完善。

    3. 核心类
      编解码、netty配置信息、通信类、handler处理器

    4. 核心代码

    工具类Crc16Utils:

    import java.nio.ByteBuffer;
    import java.nio.ByteOrder;
    
    public class Crc16Utils {
    
        private static final byte[] CRC_HI = {0x00, (byte) 0xC1, (byte) 0x81,
                (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
                (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00,
                (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0,
                (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81,
                (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
                (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01,
                (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1,
                (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81,
                (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
                (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01,
                (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0,
                (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81,
                (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
                (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00,
                (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0,
                (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81,
                (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
                (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00,
                (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1,
                (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80,
                (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
                (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01,
                (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1,
                (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81,
                (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
                (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00,
                (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1,
                (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80,
                (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
                (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01,
                (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1,
                (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81,
                (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
                (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00,
                (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0,
                (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81,
                (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
                (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00,
                (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0,
                (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80,
                (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
                (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00,
                (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1,
                (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80,
                (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
                (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00,
                (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0,
                (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81,
                (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
                (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00,
                (byte) 0xC1, (byte) 0x81, (byte) 0x40};
        private static final byte[] CRC_LO = {(byte) 0x00, (byte) 0xC0,
                (byte) 0xC1, (byte) 0x01, (byte) 0xC3, (byte) 0x03, (byte) 0x02,
                (byte) 0xC2, (byte) 0xC6, (byte) 0x06, (byte) 0x07, (byte) 0xC7,
                (byte) 0x05, (byte) 0xC5, (byte) 0xC4, (byte) 0x04, (byte) 0xCC,
                (byte) 0x0C, (byte) 0x0D, (byte) 0xCD, (byte) 0x0F, (byte) 0xCF,
                (byte) 0xCE, (byte) 0x0E, (byte) 0x0A, (byte) 0xCA, (byte) 0xCB,
                (byte) 0x0B, (byte) 0xC9, (byte) 0x09, (byte) 0x08, (byte) 0xC8,
                (byte) 0xD8, (byte) 0x18, (byte) 0x19, (byte) 0xD9, (byte) 0x1B,
                (byte) 0xDB, (byte) 0xDA, (byte) 0x1A, (byte) 0x1E, (byte) 0xDE,
                (byte) 0xDF, (byte) 0x1F, (byte) 0xDD, (byte) 0x1D, (byte) 0x1C,
                (byte) 0xDC, (byte) 0x14, (byte) 0xD4, (byte) 0xD5, (byte) 0x15,
                (byte) 0xD7, (byte) 0x17, (byte) 0x16, (byte) 0xD6, (byte) 0xD2,
                (byte) 0x12, (byte) 0x13, (byte) 0xD3, (byte) 0x11, (byte) 0xD1,
                (byte) 0xD0, (byte) 0x10, (byte) 0xF0, (byte) 0x30, (byte) 0x31,
                (byte) 0xF1, (byte) 0x33, (byte) 0xF3, (byte) 0xF2, (byte) 0x32,
                (byte) 0x36, (byte) 0xF6, (byte) 0xF7, (byte) 0x37, (byte) 0xF5,
                (byte) 0x35, (byte) 0x34, (byte) 0xF4, (byte) 0x3C, (byte) 0xFC,
                (byte) 0xFD, (byte) 0x3D, (byte) 0xFF, (byte) 0x3F, (byte) 0x3E,
                (byte) 0xFE, (byte) 0xFA, (byte) 0x3A, (byte) 0x3B, (byte) 0xFB,
                (byte) 0x39, (byte) 0xF9, (byte) 0xF8, (byte) 0x38, (byte) 0x28,
                (byte) 0xE8, (byte) 0xE9, (byte) 0x29, (byte) 0xEB, (byte) 0x2B,
                (byte) 0x2A, (byte) 0xEA, (byte) 0xEE, (byte) 0x2E, (byte) 0x2F,
                (byte) 0xEF, (byte) 0x2D, (byte) 0xED, (byte) 0xEC, (byte) 0x2C,
                (byte) 0xE4, (byte) 0x24, (byte) 0x25, (byte) 0xE5, (byte) 0x27,
                (byte) 0xE7, (byte) 0xE6, (byte) 0x26, (byte) 0x22, (byte) 0xE2,
                (byte) 0xE3, (byte) 0x23, (byte) 0xE1, (byte) 0x21, (byte) 0x20,
                (byte) 0xE0, (byte) 0xA0, (byte) 0x60, (byte) 0x61, (byte) 0xA1,
                (byte) 0x63, (byte) 0xA3, (byte) 0xA2, (byte) 0x62, (byte) 0x66,
                (byte) 0xA6, (byte) 0xA7, (byte) 0x67, (byte) 0xA5, (byte) 0x65,
                (byte) 0x64, (byte) 0xA4, (byte) 0x6C, (byte) 0xAC, (byte) 0xAD,
                (byte) 0x6D, (byte) 0xAF, (byte) 0x6F, (byte) 0x6E, (byte) 0xAE,
                (byte) 0xAA, (byte) 0x6A, (byte) 0x6B, (byte) 0xAB, (byte) 0x69,
                (byte) 0xA9, (byte) 0xA8, (byte) 0x68, (byte) 0x78, (byte) 0xB8,
                (byte) 0xB9, (byte) 0x79, (byte) 0xBB, (byte) 0x7B, (byte) 0x7A,
                (byte) 0xBA, (byte) 0xBE, (byte) 0x7E, (byte) 0x7F, (byte) 0xBF,
                (byte) 0x7D, (byte) 0xBD, (byte) 0xBC, (byte) 0x7C, (byte) 0xB4,
                (byte) 0x74, (byte) 0x75, (byte) 0xB5, (byte) 0x77, (byte) 0xB7,
                (byte) 0xB6, (byte) 0x76, (byte) 0x72, (byte) 0xB2, (byte) 0xB3,
                (byte) 0x73, (byte) 0xB1, (byte) 0x71, (byte) 0x70, (byte) 0xB0,
                (byte) 0x50, (byte) 0x90, (byte) 0x91, (byte) 0x51, (byte) 0x93,
                (byte) 0x53, (byte) 0x52, (byte) 0x92, (byte) 0x96, (byte) 0x56,
                (byte) 0x57, (byte) 0x97, (byte) 0x55, (byte) 0x95, (byte) 0x94,
                (byte) 0x54, (byte) 0x9C, (byte) 0x5C, (byte) 0x5D, (byte) 0x9D,
                (byte) 0x5F, (byte) 0x9F, (byte) 0x9E, (byte) 0x5E, (byte) 0x5A,
                (byte) 0x9A, (byte) 0x9B, (byte) 0x5B, (byte) 0x99, (byte) 0x59,
                (byte) 0x58, (byte) 0x98, (byte) 0x88, (byte) 0x48, (byte) 0x49,
                (byte) 0x89, (byte) 0x4B, (byte) 0x8B, (byte) 0x8A, (byte) 0x4A,
                (byte) 0x4E, (byte) 0x8E, (byte) 0x8F, (byte) 0x4F, (byte) 0x8D,
                (byte) 0x4D, (byte) 0x4C, (byte) 0x8C, (byte) 0x44, (byte) 0x84,
                (byte) 0x85, (byte) 0x45, (byte) 0x87, (byte) 0x47, (byte) 0x46,
                (byte) 0x86, (byte) 0x82, (byte) 0x42, (byte) 0x43, (byte) 0x83,
                (byte) 0x41, (byte) 0x81, (byte) 0x80, (byte) 0x40};
    
        public static short calcCrc16(byte[] data) {
            int uIndex;
            byte uchCRCHi = (byte) 0xFF;
            byte uchCRCLo = (byte) 0xFF;
            for (int i = 0; i < data.length; i++) {
                uIndex = (uchCRCHi ^ data[i]) & 0xFF;
    
                uchCRCHi = (byte) (uchCRCLo ^ CRC_HI[uIndex]);
                uchCRCLo = CRC_LO[uIndex];
            }
            int crc = ((((int) uchCRCLo) << 8 | (((int) uchCRCHi) & 0xFF))) & 0xFFFF;
            return (short) crc;
        }
    
        static public short calcCrc16ByLittleEndian(byte[] data) {
    
            short res = Crc16Utils.calcCrc16(data);
    
            ByteOrder order = ByteOrder.LITTLE_ENDIAN;
            ByteBuffer buf = ByteBuffer.allocate(2).order(order);
            buf.putShort(res);
    
            byte[] bytes = new byte[2];
            bytes[0] = buf.get(1);
            bytes[1] = buf.get(0);
    
            res = ByteBuffer.wrap(bytes).order(order).getShort();
    
            return res;
        }
    }
    

    编码类:

    import common.util.Crc16Utils;
    import io.netty.buffer.ByteBuf;
    import io.netty.channel.ChannelHandlerContext;
    import io.netty.handler.codec.ByteToMessageDecoder;
    
    import java.nio.charset.Charset;
    import java.util.List;
    
    public class MessageDecoder extends ByteToMessageDecoder {
    
        private final Charset charset;
    
        /**
         * Creates a new instance with the current system character set.
         */
        public MessageDecoder() {
            this(Charset.defaultCharset());
        }
    
        /**
         * Creates a new instance with the specified character set.
         */
        public MessageDecoder(Charset charset) {
            if (charset == null) {
                throw new NullPointerException("charset");
            }
            this.charset = charset;
        }
    
        @Override
        protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List<Object> out) throws Exception {
            // 可读长度必须大于基本长度
            if (buffer.readableBytes() >= SelfDefinedProtocol.MIN_LENGTH) {
                // 防止socket字节流攻击
                // 防止,客户端传来的数据过大
                if (buffer.readableBytes() > 2048) {
                    buffer.skipBytes(buffer.readableBytes());
                }
                // 记录包头开始的index
                int beginReader;
                while (true) {
                    // 获取包头开始的index
                    beginReader = buffer.readerIndex();
                    // 标记包头开始的index
                    buffer.markReaderIndex();
                    // 读到了协议的开始标志,结束while循环
                    if (buffer.readShort() == SelfDefinedProtocol.HEAD_DATA) {
                        break;
                    }
                    // 未读到包头,略过一个字节
                    // 每次略过,一个字节,去读取,包头信息的开始标记
                    buffer.resetReaderIndex();
                    buffer.readByte();
    
                    // 当略过,一个字节之后,
                    // 数据包的长度,又变得不满足
                    // 此时,应该结束。等待后面的数据到达
                    if (buffer.readableBytes() < SelfDefinedProtocol.MIN_LENGTH) {
                        return;
                    }
                }
    
                // 消息的长度
                int length = buffer.readShort();
                // 判断请求数据包数据是否到齐
                if (buffer.readableBytes() < length) {
                    // 还原读指针
                    buffer.readerIndex(beginReader);
                    return;
                }
    
                // 版本号
                byte version = buffer.readByte();
    
                // 读取data数据
                byte[] data = new byte[length];
                buffer.readBytes(data);
    
                // 读取crc校验
                short crcValue = buffer.readShort();
    
                byte[] newBytes = new byte[data.length + 1];
                newBytes[0] = version;
                for (int i = 1; i < newBytes.length; i++) {
                    newBytes[i] = data[i - 1];
                }
                short calcCrcValue = Crc16Utils.calcCrc16(data);
                SelfDefinedProtocol protocol = new SelfDefinedProtocol(Short.valueOf(data.length+""), data);
                out.add(protocol);
            }
        }
    }
    
    import common.util.Crc16Utils;
    import io.netty.buffer.ByteBuf;
    import io.netty.channel.ChannelHandlerContext;
    import io.netty.handler.codec.MessageToByteEncoder;
    
    import java.nio.charset.Charset;
    
    public class MessageEncoder extends MessageToByteEncoder<SelfDefinedProtocol> {
        private final Charset charset;
    
        /**
         * Creates a new instance with the current system character set.
         */
        public MessageEncoder() {
            this(Charset.defaultCharset());
        }
    
        /**
         * Creates a new instance with the specified character set.
         */
        public MessageEncoder(Charset charset) {
            if (charset == null) {
                throw new NullPointerException("charset");
            }
            this.charset = charset;
        }
    
        @Override
        protected void encode(ChannelHandlerContext ctx, SelfDefinedProtocol msg, ByteBuf out) throws Exception {
    
            // 写入消息自定义的具体内容  
            // steep1.写入消息的开头的信息标志(int类型)
            out.writeShort(msg.getHeadData());
            // steep2.写入消息的长度(int类型)
            out.writeShort(msg.getContentLength());
            // steep3.写入协议版本(byte[] 类型)
            out.writeByte(msg.getVersion());
            // steep4.写入消息的内容(byte[] 类型)
            out.writeBytes(msg.getContent());
            // steep5.写入消息内容的crc校验(short 类型)
            byte[] data = msg.getContent();
            byte[] newBytes = new byte[data.length + 1];
            newBytes[0] = SelfDefinedProtocol.VERSION;
            for (int i = 1; i < newBytes.length; i++) {
                newBytes[i] = data[i - 1];
            }
            short calcCrcValue = Crc16Utils.calcCrc16(data);
            out.writeShort(calcCrcValue);
            // steep6.写入消息的结尾的信息标志(int类型)
            out.writeShort(msg.getTailData());
        }
    }
    
    

    采用spring ymal配置文件方式配置netty服务器配置

    import io.netty.bootstrap.ServerBootstrap;
    import io.netty.channel.ChannelOption;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.nio.NioServerSocketChannel;
    import io.netty.handler.codec.string.StringDecoder;
    import io.netty.handler.codec.string.StringEncoder;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
    import org.springframework.stereotype.Component;
    
    import java.net.InetSocketAddress;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Set;
    
    /**
     * 读取yml配置文件中的信息
     */
    @Component
    @ConfigurationProperties(prefix = "netty")
    public class NettyConfig {
    
        private int port;
    
        private int bossCount = 2;
    
        private int workerCount = 2;
    
        @Value("${netty.port:}")
        private int tcpPort;
    
        @Value("${netty.keepalive:true}")
        private boolean keepAlive ;
    
        @Value("${netty.backlog:}")
        private int backlog;
    
        @Autowired
        @Qualifier("springProtocolInitializer")
        private StringProtocolInitalizer protocolInitalizer;
    
        /**
         * bootstrap配置
         * @return
         */
        @SuppressWarnings("unchecked")
        @Bean(name = "serverBootstrap")
        public ServerBootstrap bootstrap() {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup(), workerGroup())
                    .channel(NioServerSocketChannel.class)
                    .childHandler(protocolInitalizer);
            Map<ChannelOption<?>, Object> tcpChannelOptions = tcpChannelOptions();
            Set<ChannelOption<?>> keySet = tcpChannelOptions.keySet();
            for (@SuppressWarnings("rawtypes")
                    ChannelOption option : keySet) {
                b.option(option, tcpChannelOptions.get(option));
            }
            return b;
        }
    
        @Bean(name = "bossGroup", destroyMethod = "shutdownGracefully")
        public NioEventLoopGroup bossGroup() {
            return new NioEventLoopGroup(bossCount);
        }
    
        @Bean(name = "workerGroup", destroyMethod = "shutdownGracefully")
        public NioEventLoopGroup workerGroup() {
            return new NioEventLoopGroup(workerCount);
        }
    
        @Bean(name = "tcpSocketAddress")
        public InetSocketAddress tcpPort() {
            return new InetSocketAddress(tcpPort);
        }
    
        @Bean(name = "tcpChannelOptions")
        public Map<ChannelOption<?>, Object> tcpChannelOptions() {
            Map<ChannelOption<?>, Object> options = new HashMap<ChannelOption<?>, Object>();
            options.put(ChannelOption.SO_KEEPALIVE, keepAlive);
            options.put(ChannelOption.SO_BACKLOG, backlog);
            return options;
        }
    
        @Bean(name = "stringEncoder")
        public StringEncoder stringEncoder() {
            return new StringEncoder();
        }
    
        @Bean(name = "stringDecoder")
        public StringDecoder stringDecoder() {
            return new StringDecoder();
        }
    
        /**
         * Necessary to make the Value annotations work.
         *
         * @return
         */
        @Bean
        public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
            return new PropertySourcesPlaceholderConfigurer();
        }
    }
    

    自定义报文协议

    参考《NMEA协议》

    NMEA协议的基本格式

    • 以$或者!开头,以结尾
    • 在开始字符与结束字符之间,为一组以逗号分隔的字符串,例如:
      • $GPAAM,A,A,0.10,N,WPTNME*32
      • 因为回车+换行无法显示,因此实际上上面的例子中32后面是回车+换行
      • 在$与*中间的字符,为实际传输的信息,*之后的信息为校验码,有些NMEA0183协议有校验码,有些没有校验码,也不是所有的设备及所有的
    • 分为四种语句
      • 参数语句,即类似上述例子中的语句,以$开头,前两个字符为发送设备代号,如GP为GPS,后面紧跟的三个字符(上例中为AAM)是语句的类型,之后的每个逗号分隔的字段都是一个信息内容
      • 封装语句,以!开头,例如!AIVDM,1,1,B,16:>>s5Oh08dLO8AsMAVqptj0@>p,0*67,在B以后的内容为封装信息,需要在解析并适当合并了逗号分隔的信息之后另外解析
      • 查询语句,格式为$Q,*
      • 私有语句,以$或!开头,紧接P[,”^”,”,”]”*""

    采用的报文字段含义:

    内容格式及符号备注
    消息索引llll四位整数
    消息内容SSSSSSS字符串标识
    时间hhmmss.ss时分秒
    变长数x.x字段长度可变,例如73,73.0

    数据源可能是TCP、串口、文件或者其它类型,在本系统采用TCP协议。

    报文编解码流程:
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iKMR01PM-1578401721351)(https://note.youdao.com/yws/api/personal/file/584CC330E154402DB12F774F26AEC557?method=download&shareKey=d91978252e067e5c7f47d70f66c28959)]

    /**
     * <pre>
     * 自定义报文协议
     *  数据包格式
     * +——----——+——-----——+——----——+
     * |协议开始标志|  长度   |  版本    |   数据   |  crc校验 | 协议结束标志 |
     * |-----2------|----2----|----1-----|----N-----|-----2----|-------2------|
     * +——----——+——-----——+——----——+
     * 1.协议开始标志head_data,为int类型的数据,16进制表示为0X76
     * 2.传输数据的长度contentLength,int类型
     * 3.要传输的数据
     * </pre>
     */
    public class SelfDefinedProtocol {
        /**
         * 最小长度
         */
        public static final short MIN_LENGTH = 9;
        /**
         * 消息的开头标志
         */
        public static final short HEAD_DATA = 0x2A2A;
        /**
         * 消息的结束标志
         */
        public static final short TAIL_DATA = 0x2323;
        /**
         * 消息的版本号
         */
        public static final byte VERSION = '1';
    
        /**
         * 消息的开头的信息标志
         */
        private short headData = HEAD_DATA;
        /**
         * 消息的长度
         */
        private short contentLength;
        /**
         * 版本号
         */
        private byte version = VERSION;
        /**
         * 消息的内容
         */
        private byte[] content;
        /**
         * crc消息的内容
         */
        private short crcContent;
        /**
         * 消息的结束的信息标志
         */
        private short tailData = TAIL_DATA;
    
        public SelfDefinedProtocol(short contentLength, byte[] content) {
            this.contentLength = contentLength;
            this.content = content;
        }
    
        public short getHeadData() {
            return headData;
        }
    
        public void setHeadData(short headData) {
            this.headData = headData;
        }
    
        public short getContentLength() {
            return contentLength;
        }
    
        public void setContentLength(short contentLength) {
            this.contentLength = contentLength;
        }
    
        public byte getVersion() {
            return version;
        }
    
        public void setVersion(byte version) {
            this.version = version;
        }
    
        public byte[] getContent() {
            return content;
        }
    
        public void setContent(byte[] content) {
            this.content = content;
        }
    
        public short getCrcContent() {
            return crcContent;
        }
    
        public void setCrcContent(short crcContent) {
            this.crcContent = crcContent;
        }
    
        public short getTailData() {
            return tailData;
        }
    
        public void setTailData(short tailData) {
            this.tailData = tailData;
        }
    
        public static SelfDefinedProtocol newSuccess() {
            byte[] content = Result.newSuccess().toString().getBytes();
            SelfDefinedProtocol selfDefinedProtocol = new SelfDefinedProtocol((short)content.length,content);
            return  selfDefinedProtocol;
        }
    
        public static SelfDefinedProtocol newFail() {
            byte[] content = Result.newFaild().toString().getBytes();
            SelfDefinedProtocol selfDefinedProtocol = new SelfDefinedProtocol((short)content.length,content);
            return  selfDefinedProtocol;
        }
    }
    
    
    展开全文
  • netty基本组件介绍中,我们大致了解了netty的一些基本组件,今天我们来搭建一个基于nettyTcp服务端程序,通过代码来了解和熟悉这些组件的功能和使用方法。 首先我们自己创建一个Server类,命名为TCPServer 第...

    netty基本组件介绍中,我们大致了解了netty的一些基本组件,今天我们来搭建一个基于netty的Tcp服务端程序,通过代码来了解和熟悉这些组件的功能和使用方法。

    首先我们自己创建一个Server类,命名为TCPServer

    第一步初始化ServerBootstrap,ServerBootstrap是netty中的一个服务器引导类,对ServerBootstrap的实例化就是创建netty服务器的入口

    public class TCPServer {
        private Logger log = LoggerFactory.getLogger(getClass());
        //端口号
        private int port=5080;
        //服务器运行状态
        private volatile boolean isRunning = false; 
        //处理Accept连接事件的线程,这里线程数设置为1即可,netty处理链接事件默认为单线程,过度设置反而浪费cpu资源
        private final EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        //处理hadnler的工作线程,其实也就是处理IO读写 。线程数据默认为 CPU 核心数乘以2
        private final EventLoopGroup workerGroup = new NioEventLoopGroup();
         
        public void init() throws Exception{
            //创建ServerBootstrap实例
            ServerBootstrap serverBootstrap=new ServerBootstrap();
            //初始化ServerBootstrap的线程组
            serverBootstrap.group(workerGroup,workerGroup);//
            //设置将要被实例化的ServerChannel类
            serverBootstrap.channel(NioServerSocketChannel.class);//
            //在ServerChannelInitializer中初始化ChannelPipeline责任链,并添加到serverBootstrap中
            serverBootstrap.childHandler(new ServerChannelInitializer());
            //标识当服务器请求处理线程全满时,用于临时存放已完成三次握手的请求的队列的最大长度
            serverBootstrap.option(ChannelOption.SO_BACKLOG, 1024);
            // 是否启用心跳保活机机制
            serverBootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);    
            //绑定端口后,开启监听
            ChannelFuture channelFuture = serverBootstrap.bind(port).sync();
            if(channelFuture.isSuccess()){
                System.out.println("TCP服务启动 成功---------------");
            }
        }
        
        /**
         * 服务启动
         */
        public synchronized void startServer() {
            try {
                  this.init();
            }catch(Exception ex) {
                
            }
        }
        
        /**
         * 服务关闭
         */
        public synchronized void stopServer() {
            if (!this.isRunning) {
                throw new IllegalStateException(this.getName() + " 未启动 .");
            }
            this.isRunning = false;
            try {
                Future<?> future = this.workerGroup.shutdownGracefully().await();
                if (!future.isSuccess()) {
                    log.error("workerGroup 无法正常停止:{}", future.cause());
                }
    
                future = this.bossGroup.shutdownGracefully().await();
                if (!future.isSuccess()) {
                    log.error("bossGroup 无法正常停止:{}", future.cause());
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            this.log.info("TCP服务已经停止...");
        }
        
        private String getName() {
            return "TCP-Server";
        }
    }

    上面的代码中主要使用到的ServerBootstrap类的方法有以下这些:

    group  :设置SeverBootstrap要用到的EventLoopGroup,也就是定义netty服务的线程模型,处理Acceptor链接的主"线程池"以及用于I/O工作的从"线程池";

    channel:设置将要被实例化的SeverChannel类;

    option :指定要应用到新创建SeverChannel的ChannelConfig的ChannelOption.其实也就是服务本身的一些配置;

    chidOption:子channel的ChannelConfig的ChannelOption。也就是与客户端建立的连接的一些配置;

    childHandler:设置将被添加到已被接收的子Channel的ChannelPipeline中的ChannelHandler,其实就是让你在里面定义处理连接收发数据,需要哪些ChannelHandler按什么顺序去处理;

    第二步接下来我们实现ServerChannelInitializer类,这个类继承实现自netty的ChannelInitializer抽象类,这个类的作用就是对channel(连接)的ChannelPipeline进行初始化工作,说白了就是你要把处理数据的方法添加到这个任务链中去,netty才知道每一步拿着socket连接和数据去做什么。

    @ChannelHandler.Sharable
    public class ServerChannelInitializer extends ChannelInitializer<SocketChannel> {
        static final EventExecutorGroup group = new DefaultEventExecutorGroup(2);
         
        public ServerChannelInitializer() throws InterruptedException {
        }
        
        @Override
        protected void initChannel(SocketChannel socketChannel) throws Exception {    
            ChannelPipeline pipeline = socketChannel.pipeline();
            //IdleStateHandler心跳机制,如果超时触发Handle中userEventTrigger()方法
            pipeline.addLast("idleStateHandler",
                    new IdleStateHandler(15, 0, 0, TimeUnit.MINUTES));
            // netty基于分割符的自带解码器,根据提供的分隔符解析报文,这里是0x7e;1024表示单条消息的最大长度,解码器在查找分隔符的时候,达到该长度还没找到的话会抛异常
    //        pipeline.addLast(
    //                new DelimiterBasedFrameDecoder(1024, Unpooled.copiedBuffer(new byte[] { 0x7e }),
    //                        Unpooled.copiedBuffer(new byte[] { 0x7e })));
             //自定义编解码器
             pipeline.addLast(
                     new MessagePacketDecoder(),
                     new MessagePacketEncoder()
                    );
            //自定义Hadler
            pipeline.addLast("handler",new TCPServerHandler());
            //自定义Hander,可用于处理耗时操作,不阻塞IO处理线程
            pipeline.addLast(group,"BussinessHandler",new BussinessHandler());
        }
    }

    这里我们注意下

    pipeline.addLast(group,"BussinessHandler",new BussinessHandler());

    在这里我们可以把一些比较耗时的操作(如存储、入库)等操作放在BussinessHandler中进行,因为我们为它单独分配了EventExecutorGroup 线程池执行,所以说即使这里发生阻塞,也不会影响TCPServerHandler中数据的接收。

    最后就是各个部分的具体实现

    解码器的实现:

    public class MessagePacketDecoder extends ByteToMessageDecoder
    {
    
        public MessagePacketDecoder() throws Exception
        {
        }
    
        @Override
        protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List<Object> out) throws Exception
        {
            try {
                if (buffer.readableBytes() > 0) {
                    // 待处理的消息包
                    byte[] bytesReady = new byte[buffer.readableBytes()];
                    buffer.readBytes(bytesReady);
                    //这之间可以进行报文的解析处理
                    out.add(bytesReady );
                }
            }finally {
                
            }
        }
    
    
    }

    编码器的实现

    public class MessagePacketEncoder extends MessageToByteEncoder<Object>
    {
        public MessagePacketEncoder()
        {
        }
    
        @Override
        protected void encode(ChannelHandlerContext ctx, Object msg, ByteBuf out) throws Exception
        {
            try {
                //在这之前可以实现编码工作。
                out.writeBytes((byte[])msg); 
            }finally {
                
            }  
        }
    }

    TCPServerHandler的实现

        public class TCPServerHandler extends ChannelInboundHandlerAdapter {
            public TCPServerHandler() {
            }
    
            @Override
            public void channelRead(ChannelHandlerContext ctx, Object source) throws Exception {
                // 拿到传过来的msg数据,开始处理
                ByteBuf recvmg = (ByteBuf) source;// 转化为ByteBuf
                ctx.writeAndFlush(respmsg);// 收到及发送,这里如果没有writeAndFlush,上面声明的ByteBuf需要ReferenceCountUtil.release主动释放
    
            }
        }

    BussinessHandler的实现与TCPServerHandler基本类似,它可以处理一些相对比较耗时的操作,我们这里就不实现了。

    通过以上的代码我们可以看到,一个基于netty的TCP服务的搭建基本就是三大块:

    1、对引导服务器类ServerBootstrap的初始化;

    2、对ChannelPipeline的定义,也就是把多个ChannelHandler组成一条任务链;

    3、对 ChannelHandler的具体实现,其中可以有编解码器,可以有对收发数据的业务处理逻辑;

    以上代码只是在基于netty框架搭建一个最基本的TCP服务,其中包含了一些netty基本的特性和功能,当然这只是netty运用的一个简单的介绍,如有不正确的地方还望指出与海涵。

     

    关注微信公众号,查看更多技术文章。

    转载于:https://www.cnblogs.com/dafanjoy/p/9729400.html

    展开全文
  • 2.服务器端向客户端发送数据,客户端接收不到。这时候,可以确认一下ctx.write()方法中传递的参数是不是ByteBuf类型 原代码: ctx.writeAndFlush(data); 修改之后: ByteBuf responseBuf=Unpooled....

    1.客户端第一次连接能进入到handler的方法中,但是一旦这个客户端关闭了连接,那么重新连接的时候就无法再进入到server的handler中了,需要重启server之后才能再次进入。这时候,可以看一下设置handler的方式

    原代码:

    serverBootstrap.childHandler(new MsgHandler());

    修改之后:

    serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            socketChannel.pipeline().addLast(new MsgHandler());
                        }
                    });

     

    2.服务器端向客户端发送数据,客户端接收不到。这时候,可以确认一下ctx.write()方法中传递的参数是不是ByteBuf类型

    原代码:

    ctx.writeAndFlush(data);

    修改之后:

    ByteBuf responseBuf=Unpooled.copiedBuffer(data);
    ctx.writeAndFlush(responseBuf);

     

    展开全文
  • 这一般不用于TCP服务器。 // SO_REUSEADDR允许完全重复的捆绑:当一个IP地址和端口绑定到某个套接口上时, // 还允许此IP地址和端口捆绑到另一个套接口上。一般来说,这个特性仅在支持多播的系统上才有, /...
  • Java前端服务器:使用Spring Boot 2.0作为基础框架,使用Netty构造TCP服务器与上万台设备组成的通信,采用自定义帧格式。 基于Vue.js的Web前端“ SPA”单页应用程序:绚丽的现代化SPA应用程序,可视化展示服务器...
  • netty搭建TCP、UDP服务

    2020-09-23 17:05:21
    Java异步NIO框架Netty实现高性能高并发,通过netty搭建TCP、UDP服务,支持物联网设备上行,下行
  • 使用 Netty 搭建 TCP 服务器 使用 Protobuf 进行数据交互 使用 Mybatis 自动生成插件 Other maven mirror 设置 <id>alimaven <name>aliyun maven <url>...
  • 文章目录简介netty中的websocketwebsocket的版本...通过Websocket我们可以实现客户端和服务器端的即时通讯,免除了客户端多次轮循带来的性能损耗。 既然websocket这么优秀,那么怎么在netty中使用websocket呢?
  • Netty编写TCP服务器和SpringBoot整合

    千次阅读 2020-03-14 17:41:44
    以前在写项目的时候用到过,这个tcp服务器的功能主要就是不间断的完成客户端发来的TCP连接请求,先是使用的阻塞式IO,然后又改为NIO,NIO写的时候出现了一些问题,就改用为Netty了 前言:此文仅提供思路,环境...
  • Springboot + Netty 搭建websocket服务器 入门 废话少说直接贴代码,会用再说 导入pom <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <...
  • 了解MQTT协议以及利用Netty搭建MQTT服务器MQTT协议协议简介设计原则灵活的发布订阅和主题设计带宽消耗最小化三个可选的 QoS 等级会话保持在线状态感知开源 MQTT 服务器MQTT 发布订阅模式介绍发布订阅模式消息路由...
  • springboot+Netty搭建web服务器实现物联网温湿度采集

    千次阅读 多人点赞 2020-07-01 12:44:56
    Netty服务器搭建 NettyServer.java /** * @author cx * @Time 2020/6/29 22:00 * @Description netty 服务器配置 */ public class NettyServer { public void start(InetSocketAddress socketAddre
  • 集群设备管理云平台「Java、SPA、Spring、Netty、Vue.js 2.0、Element 2.0」项目描述Java & Vue.js 全栈项目,大规模集群设备管理云平台,由以下几部分组成:Java 后端服务器、基于 Vue.js 的 Web 前端「SPA」...
  • 在上一篇中我们对WebSocket协议进行了介绍,在开始之前,...本篇我们就基于Netty搭建WebSocket服务的完整案例来实现消息的主动推送功能,并在其中贯穿一下上一篇中的WebSocket的部分理论知识! 一、案例实现 2.1...
  • Springboot+Netty搭建基于TCP协议的服务端(一)

    万次阅读 多人点赞 2019-06-02 19:37:20
    Netty是业界最流行的nio框架之一,它具有功能强大、性能优异、可定制性和可扩展性的优点 Netty的优点: 1.API使用简单,开发入门门槛低。 2.功能十分强大,预置多种编码解码功能,支持多种主流协议。 3.可定制、...
  • 前言使用idea快速搭建基于maven的netty服务器项目1.新建空白maven项目file-new-project选择maven空白项目,输入groupid和artifactid,一路点next 2.引入netty maven 依赖pom.xml 文件加入netty-all 依赖io....
  • Netty创建TCP服务端

    千次阅读 2019-07-09 14:50:53
    Netty的服务器其中之一便是TCP服务器。想要创建TCP服务器你必须: 创建一个EventLoopGroup 创建和配置ServerBootstrap 创建一个ChannelInitializer 启动服务器 下面是一个完整的使用Netty创建TCP服务器的代码例子...
  • Netty5.0搭建服务器

    2017-05-05 11:17:27
    也就是说,Netty 是一个基于NIO的客户,服务器端编程框架,使用Netty 可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户,服务端应用。Netty相当简化和流线化了网络应用的编程开发过程,例如,...
  • 基于nettytcp框架搭建-面向接口编程之多类型netty服务面向接口编程之多类型netty服务面向接口编程业务说明代码 面向接口编程之多类型netty服务 面向接口编程 面向接口编程有不少优点 1、降低耦合度,不同的实现类...
  • Netty创建TCP客户端

    千次阅读 2019-07-09 14:52:57
    Netty可以用来创建TCP客户端。这里我们将说明如何使用Netty创建一个TCP客户端。使用Netty创建客户端需要一下几个步骤: 创建一个EventLoopGroup 创建和配置一个Bootstrap 创建一个ChannelInitializer 启动客户端 ...
  • 世上无难事,只要肯登攀。...搭建 HTTP 服务器,配置相关参数并启动。 从浏览器或者终端发起 HTTP 请求。 成功得到服务端的响应结果。 准备工作 先创建一个maven项目,引入netty依赖,这里使用4.1.52...
  • IO编程 场景:客户端每隔两秒发送一个带有时间戳的"hello world"给服务端,服务端收到之后打印。 先后运行IOServer.java和IOClient.java可看到效果。 public class IOServer { public static void main(String...
  • 基于netty简单的http服务器搭建简介一、http协议简介1.1 HttpRequest1.2 HttpResponse二、服务端开发三、测试 简介  HTTP是一个超文本传输协议,是一种建立在TCP传输协议之上的应用层协议。http是目前web的主流协议...
  • netty搭建

    2017-09-12 09:09:25
    工作中需要使用netty socket搭建一个聊天功能,大部分内容为引用,会在文章末尾把引用链接写出 首先引用http://www.cnblogs.com/damowang/p/6226167.html实现一个聊天功能
  • 搭建netty服务器

    2018-07-18 13:44:33
    io.netty&lt;/groupId&gt; &lt;artifactId&gt;netty-all&lt;/artifactId&gt; &lt;version&gt;5.0.0.Alpha2&lt;/version&gt; &lt;/dependency&gt;
  • 本篇文章主要介绍了spring+netty服务器搭建的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • 快速搭建 netty服务器

    2020-02-24 12:58:38
    使用idea快速搭建基于maven的netty服务器项目 1.新建空白maven项目 file-new-project 选择maven空白项目,输入groupid和artifactid,一路点next 2.引入netty maven 依赖 pom.xml 文件加入netty-all 依赖 io....
  • netty实现tcp长连接和心跳检测

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,779
精华内容 1,511
关键字:

netty搭建tcp服务器