netty-实例

一,基本格式:

1,主要jar包:

<dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>4.1.30.Final</version>
        </dependency>

2,主要程序

客户端:

package com.xl.test01.com.xl.nettytest01;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;

public class nettyClient {
    public static void main(String[] args) throws InterruptedException {
        //客户端需要一个事件循环组
        EventLoopGroup eventExecutors = new NioEventLoopGroup();
        try {
            //创建客户端启动对象,客户端使用的不是ServerBootstrap,而是BootStrap
            Bootstrap bootstrap = new Bootstrap();

            //设置相关参数
            bootstrap.group(eventExecutors)//设置线程组
                    .channel(NioSocketChannel.class)//设置客户端通道的实现类
                    .handler(new ChannelInitializer<SocketChannel>() {
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            socketChannel.pipeline().addLast(new nettyClientHandle());
                        }
                    });
            System.out.println("客户端 ok....");
            //启动客户端连接服务器端
            ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 6668).sync();
            //给关闭通道增加一个监听
            channelFuture.channel().closeFuture().sync();
        } finally {
            eventExecutors.shutdownGracefully();
        }
    }
}

客户端处理器:

package com.xl.test01.com.xl.nettytest01;


import com.xl.test01.com.xl.myCar.NoBodyCar;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;


public class nettyClientHandle extends ChannelInboundHandlerAdapter {
    
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("client:" + ctx);
        ctx.writeAndFlush(Unpooled.copiedBuffer("haha", CharsetUtil.UTF_8));
      // ctx.writeAndFlush(setNoBodyCar());
    }

    //当通道有读取事件时会触发
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf buf = (ByteBuf) msg;
        System.out.println("服务器回复的消息" + buf.toString(CharsetUtil.UTF_8));
        System.out.println("服务器的地址:" + ctx.channel().remoteAddress());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}

服务器端:

package com.xl.test01.com.xl.nettytest01;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

public class nettyServer {
    public static void main(String[] args) throws InterruptedException {
        //创建BossGroup和WorkGroup
        //BossGroup负责连接,WorkerGroup负责客户端的业务处理
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup worherGroup = new NioEventLoopGroup();
        try {
            //创建服务器启动对象,配置参数
            ServerBootstrap bootstrap = new ServerBootstrap();
            //使用链式编程进行设置
            bootstrap.group(bossGroup, worherGroup) //设置两个线程组
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 128)//设置线程队列等待连接个数
                    .childOption(ChannelOption.SO_KEEPALIVE, true)//设置保持请求连接状态
                    .childHandler(new ChannelInitializer<SocketChannel>() {//创建一个通道初始化对象(匿名对象)
                        //给pipeline设置处理器
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            socketChannel.pipeline().addLast(new nettyServerHandle());
                        }
                    });//给我们的workgroup的EventLoop对应的管道设置处理器

            System.out.println("服务器 is ready");

            //绑定一个端口并且同步,生成一个ChannelFuture对象
            //启动服务器,并绑定端口
            ChannelFuture cf = bootstrap.bind(6668).sync();

            //对关闭通道进行监听
            cf.channel().closeFuture().sync();

        } finally {
            bossGroup.shutdownGracefully();
            worherGroup.shutdownGracefully();
        }
    }
}

服务器端处理器:

package com.xl.test01.com.xl.nettytest01;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;

/*
 * 自定义一个Hander,需要继承netty,规定好的某个HandlerAdapter
 *
 * */
public class nettyServerHandle extends ChannelInboundHandlerAdapter {
    //读取数据实际(这里我们可以读取客户端发送的消息)
    /*
     *1,ChannelHandlerContext ctx:上下文对象,含有管道pipeline,通道,地址
     * 2,Object msg:客户端发送过来的数据
     *
     * */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("server ctx=" + ctx);
        //将msg转成ByteBu f
        ByteBuf buf = (ByteBuf) msg;
        System.out.println("客户端发送的消息是:" + buf.toString(CharsetUtil.UTF_8));
        //System.out.println("客户端发送的消息是:"+msg);
        System.out.println("客户端地址是:" + ctx.channel().remoteAddress());

        //数据读取完毕

    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        //writeAndFlush,代表写和刷新,及将数据写入到缓存并刷新
        //对发送的数据进行编码
        ctx.writeAndFlush(Unpooled.copiedBuffer("hello,客户端", CharsetUtil.UTF_8));
    }
    //处理异常,一般需要关闭通道

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.close();
    }
}

二,我的项目:

说明:在该项目中,客户端为一个通过以太网的传送数据信息的数据采集器,我的电脑作为服务器端负责接收数据:

 <dependencies>
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>4.1.30.Final</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.9</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.71</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.2</version>
            <scope>compile</scope>
        </dependency>


        <dependency>
            <groupId>org.jboss.marshalling</groupId>
            <artifactId>jboss-marshalling</artifactId>
            <version>2.0.0.Final</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.jboss.marshalling/jboss-marshalling-serial -->
        <!-- https://mvnrepository.com/artifact/org.jboss.marshalling/jboss-marshalling-serial -->
        <dependency>
            <groupId>org.jboss.marshalling</groupId>
            <artifactId>jboss-marshalling-serial</artifactId>
            <version>2.0.9.Final</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.jboss.marshalling/jboss-marshalling -->
        <dependency>
            <groupId>org.jboss.marshalling</groupId>
            <artifactId>jboss-marshalling</artifactId>
            <version>2.0.9.Final</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/bcel/bcel -->
        <dependency>
            <groupId>bcel</groupId>
            <artifactId>bcel</artifactId>
            <version>5.1</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.slf4j/nlog4j -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>nlog4j</artifactId>
            <version>1.2.25</version>
            <scope>provided</scope>
        </dependency>



    </dependencies>
package com.xl.test01.com.xl3.nettyTest02;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

public class Serve {
    public static void main(String[] args) {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup worherGroup = new NioEventLoopGroup();
        try{
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup, worherGroup) //设置两个线程组
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 128)//设置线程队列等待连接个数
                    .childOption(ChannelOption.SO_KEEPALIVE, true)//设置保持请求连接状态
                    .childHandler(new ChannelInitializer<SocketChannel>() {//创建一个通道初始化对象(匿名对象)
                        //给pipeline设置处理器
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            socketChannel.pipeline().addLast(new ServeHandle());
                        }
                    });//给我们的workgroup的EventLoop对应的管道设置处理器

            System.out.println("服务器 is OK");
            //绑定一个端口并且同步,生成一个ChannelFuture对象
            //启动服务器,并绑定端口
            ChannelFuture cf = bootstrap.bind(8020).sync();
            //对关闭通道进行监听
            cf.channel().closeFuture().sync();

        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally{
            bossGroup.shutdownGracefully();
            worherGroup.shutdownGracefully();
        }
    }
}
package com.xl.test01.com.xl3.nettyTest02;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.unix.Buffer;
import io.netty.util.CharsetUtil;

import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

public class ServeHandle extends ChannelInboundHandlerAdapter {
    List<Byte> mylist = new LinkedList<Byte>();
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        myFunction myFunction = new myFunction();
        RespLoginCommand respLoginCommand = new RespLoginCommand();
        ByteBuf buf = (ByteBuf) msg;
        int bufLength = buf.readableBytes();
        byte[] bytes = new byte[bufLength];
        buf.getBytes(0, bytes);
        for (int i = 0; i < bytes.length; i++) {
            mylist.add(bytes[i]);
        }
        System.out.println("数据收到,下面处理数据,链表长度是: " + mylist.size());

        if (mylist.size() > 100) {
            List<Byte> newList = myFunction.getFullXDate(mylist);
            System.out.println("newList从list中分析得到的长度为: " + newList.size() + "  值为: " + newList);
            System.out.println("转换为16进制为:");
            for(int ii=0;ii<newList.size();ii++){
                System.out.println(Integer.toHexString(newList.get(ii)));
            }
            int i = myFunction.JudgeDate(newList);
            System.out.println(i);
            if (i == 1) {//发送登录请求命令
                System.out.println("登录命令匹配成功,同意登录");
                ctx.writeAndFlush(respLoginCommand.createLogRequestCode(ctx));
            }
            if (i == 2 || i == 3) {
                System.out.println("登录命令匹配失败,");
                ctx.writeAndFlush(Unpooled.copiedBuffer("登录命令匹配失败,请重新登录,", CharsetUtil.UTF_8));
            }
            if (i == 4) {//发送内容成功
                System.out.println("发送内容接收成功");
                for (int j = 13; j < newList.size(); j = j + 5) {
                    String combSS = new String();
                    for (int k = j + 3; k >= j; k--) {
                        String s = new String();
                        if (newList.get(k) >= 0) {
                            s = Integer.toHexString(newList.get(k) +51);
                        } else {//在不大于0的条件下,newlist的值转换为16进制为ffffff01,所以取后两位。
                            s = Integer.toHexString(newList.get(k) + 51).substring(Integer.toHexString(newList.get(k) + 51).length()-2);
                        }
                        // System.out.println(s);
                        if (s.length() == 1) {
                            s = "0".concat(s);
                        }
                        combSS = combSS.concat(s);
                    }
                    // System.out.println(combSS);
                    double temperature = myFunction.parseHex4(combSS.substring(0, 4));
                    double humidity = myFunction.parseHex4(combSS.substring(4, 8));
                    int n = (j - 13) / 5 + 1;
                    System.out.println("通道" + n + "的温度是" + humidity / 10 + " C");
                    System.out.println("通道" + n + "的湿度是" + temperature / 10 + "%");
                    System.out.println("**********************");

                }
                ctx.writeAndFlush(respLoginCommand.createContRequestCode(ctx));
            }
            if (i == 5 || i == 6) {
                System.out.println("发送数据内容匹配失败,");
                ctx.writeAndFlush(Unpooled.copiedBuffer("发送数据内容匹配失败,请重新登录,", CharsetUtil.UTF_8));
            }
        } else {
            System.out.println("链表长度尚未满足,继续接收数据");

        }
    }


    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {

    }

}
package com.xl.test01.com.xl3.nettyTest02;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;

public class RespLoginCommand {

    public ByteBuf createLogRequestCode(ChannelHandlerContext ctx) {
        ByteBuf byteBuf = ctx.alloc().buffer();
        byteBuf.writeByte(0x68);
        byteBuf.writeByte(0x88);
        byteBuf.writeByte(0x88);
        byteBuf.writeByte(0x88);
        byteBuf.writeByte(0x88);
        byteBuf.writeByte(0x88);
        byteBuf.writeByte(0x88);
        byteBuf.writeByte(0x68);
        byteBuf.writeByte(0x20);
        byteBuf.writeByte(6);//长度
        byteBuf.writeByte(0x33);
        byteBuf.writeByte(0x1d);
        byteBuf.writeByte(0x64);
        byteBuf.writeByte(0xc3);
        byteBuf.writeByte(0x37);
        byteBuf.writeByte(0x73);
        byteBuf.writeByte(0x647 & 0xff);
        byteBuf.writeByte(0x16);

        return byteBuf;
    }

    public ByteBuf createContRequestCode(ChannelHandlerContext ctx) {
        ByteBuf byteBuf = ctx.alloc().buffer();
        byteBuf.writeByte(0x68);
        byteBuf.writeByte(0x88);
        byteBuf.writeByte(0x88);
        byteBuf.writeByte(0x88);
        byteBuf.writeByte(0x88);
        byteBuf.writeByte(0x88);
        byteBuf.writeByte(0x88);
        byteBuf.writeByte(0x68);
        byteBuf.writeByte(0x20);
        byteBuf.writeByte(6);//长度
        byteBuf.writeByte(0x36);
        byteBuf.writeByte(0x1d);
        byteBuf.writeByte(0x64);
        byteBuf.writeByte(0xc3);
        byteBuf.writeByte(0x37);
        byteBuf.writeByte(0x73);
        byteBuf.writeByte(0x64A & 0xff);
        byteBuf.writeByte(0x16);

        return byteBuf;
    }

    public byte[] str2Bcd(String asc) {
        int len = asc.length();
        int mod = len % 2;
        if (mod != 0) {
            asc = "0" + asc;
            len = asc.length();
        }
        byte abt[] = new byte[len];
        if (len >= 2) {
            len = len / 2;
        }
        byte bbt[] = new byte[len];
        abt = asc.getBytes();
        int j, k;
        for (int p = 0; p < asc.length() / 2; p++) {
            if ((abt[2 * p] >= '0') && (abt[2 * p] <= '9')) {
                j = abt[2 * p] - '0';
            } else if ((abt[2 * p] >= 'a') && (abt[2 * p] <= 'z')) {
                j = abt[2 * p] - 'a' + 0x0a;
            } else {
                j = abt[2 * p] - 'A' + 0x0a;
            }
            if ((abt[2 * p + 1] >= '0') && (abt[2 * p + 1] <= '9')) {
                k = abt[2 * p + 1] - '0';
            } else if ((abt[2 * p + 1] >= 'a') && (abt[2 * p + 1] <= 'z')) {
                k = abt[2 * p + 1] - 'a' + 0x0a;
            } else {
                k = abt[2 * p + 1] - 'A' + 0x0a;
            }
            int a = (j << 4) + k;
            byte b = (byte) a;
            bbt[p] = b;
        }
        return bbt;
    }

}
package com.xl.test01.com.xl3.nettyTest02;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

public class myFunction {

    /**
     * @param list
     * @return 返回一条完整的数据
     */
    public List<Byte> getFullXDate(List<Byte> list) {
        List<Byte> newList = new LinkedList<Byte>();
        System.out.println("list长度为" + list.size());
        System.out.println("list内容为" + list);
        if (list.contains((byte) 0x16)) {
            int i = list.indexOf((byte) 0x16);//有多个16返回值问题
            while (i <= list.size()) {
                if (list.get(i) == (byte) 0x16 && list.get(i + 1) == (byte) 0x68 && list.get(i + 2) == (byte) 0x88) { ;
                 newList.addAll(list.subList(0, i+1));//取前i条数据
                    for (int k = 0; k <newList.size();k++) {
                      list.remove(0);
                    }
                    //list.removeAll(newList);//删除的为list中newlist中所含的所有元素。
//                    Iterator<Byte> it = list.iterator();
//                    while(it.hasNext()){
//                        Byte x = it.next();
//                        if(x.equals("del")){
//                            it.remove();
//                        }
//                    }
                    break;
                } else {
                    i++;
                    continue;
                }
            }
        } else {
            System.out.println("所发数据中不包含结束符16");
        }
//        for (int k = 0; k <= newList.size(); k++) {
//            list.remove(k);
        }
//        System.out.println(newList);
//        System.out.println(list);
//        List<Byte> subList = new ArrayList<Byte>(list.subList(0,i));
//        list.removeAll(subList);
        //   list.removeAll(newList);
//        list=list.subList(i+2,list.size());
//        System.out.println(list);
        System.out.println("修改过的list的长度为: " + list.size() + "值为: " + list);

        return newList;
    }

    /**
     * @param
     * @return 1, 登录命令匹配成功,同意登陆 2,登录命令内容匹配失败3,登录命令头部匹配失败
     * 4,发送数据匹配寄接收成功 5,发送内容匹配失败 6,发送内容匹配失败
     */
    public Integer JudgeDate(List<Byte> list) {
        Byte[] bytes = new Byte[list.size()];
        list.toArray(bytes);
        int returnId = 0;

        if (bytes[10] == (byte) 0x33 && bytes[11] == (byte) 0x1d) {
            //判断帧头
            if (bytes[0] == (byte) 0x68 && bytes[7] == (byte) 0x68) {
                int j = 0;
                for (int i = 1; i < 7; i++) {
                    if (bytes[i] == (byte) 0x88) {
                        j++;
                        continue;
                    } else {
                        break;
                    }
                }
                if (j == 6) {
                    //System.out.println("头部匹配成功");
                    // returnId = 1;
                    if (bytes[8] == (byte) 0xA0 && bytes[21] == (byte) 0x16) {
                        returnId = 1;
                        // System.out.println("经检验全部数据合法,同意登陆");
                        // ctx.writeAndFlush(respLoginCommand.createLogRequestCode(ctx));
                        //  System.out.println("客户端发送成功");
                    } else {
                        returnId = 2;
                        // System.out.println("内容匹配失败");
                    }

                } else {
                    returnId = 3;
                    //   System.out.println("头部匹配失败");
                }
            } else {
                returnId = 3;
                //System.out.println("头部匹配失败");
            }

        } else
            //判断标识码,是否为运行数据帧
            if (bytes[10] == (byte) 0x36 && bytes[11] == (byte) 0x1d) {
                if (bytes[0] == (byte) 0x68 && bytes[7] == (byte) 0x68) {
                    int j = 0;
                    for (int i = 1; i < 7; i++) {
                        if (bytes[i] == (byte) 0x88) {
                            j++;
                            continue;
                        } else {
                            break;
                        }
                    }
                    if (j == 6) {
                        // returnId = 1;
                        // System.out.println("头部匹配成功");
                        if (bytes[8] == (byte) 0xA0 && bytes[bytes.length - 1] == (byte) 0x16) {
                            returnId = 4;
                            //  System.out.println("内容匹配成功");
                            //  for (int i = 0; i < bufLength; i++) {
                            // System.out.println("接收到的数据为" + Integer.toHexString(bytes[i] - 0x33));
                            //   }
                            //  System.out.println("客户端发送运行数据成功,已收到");

                        } else {
                            returnId = 5;
                            // System.out.println("内容匹配失败");
                        }
                    } else {
                        returnId = 6;
                        //System.out.println("头部匹配失败");
                    }
                } else {
                    returnId = 6;
                    //  System.out.println("头部匹配失败");
                }
            } else {
                returnId = 6;
            }
        return returnId;
    }

    //16进制转换为10进制
    public double parseHex4(String num) {
        List<String> list = new ArrayList<String>();

        if (num.length() != 4) {
            throw new NumberFormatException("Wrong length: " + num.length() + ", must be 4.");
        }
        int ret = Integer.parseInt(num, 16);
        ret = ((ret & 0x8000) > 0) ? (ret - 0x10000) : (ret);
        return (double) ret;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值