Netty接收UDP组播数据

针对多网卡情况,绑定其中的一个网卡,接收UDP组播中的数据。

package com.demo.udp;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.InternetProtocolFamily;
import io.netty.channel.socket.nio.NioDatagramChannel;

import java.net.*;
import java.util.Enumeration;

public class UdpReceiver {
    // 组播地址
    private static final String groupIp = "225.1.2.2";
    // 组播端口号
    private static final int groupPort = 1234;
    // 本机地址
    private static final String localIp = "192.168.1.110";


    public static void main(String[] args) {
        // 组播地址
        InetSocketAddress groupAddress = new InetSocketAddress(groupIp, groupPort);

        EventLoopGroup group = new NioEventLoopGroup();

        try {
            NetworkInterface ni = NetworkInterface.getByInetAddress(InetAddress.getByName(localIp));
            Enumeration<InetAddress> addresses = ni.getInetAddresses();

            InetAddress localAddress = null;
            while (addresses.hasMoreElements()) {
                InetAddress address = addresses.nextElement();
                if (address instanceof Inet4Address) {
                    localAddress = address;
                    System.out.println("网络接口名称为:" + ni.getName());
                    System.out.println("网卡接口地址:" + address.getHostAddress());
                }
            }

            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(group)
                    .channelFactory(new ChannelFactory<NioDatagramChannel>() {
                        @Override
                        public NioDatagramChannel newChannel() {
                            return new NioDatagramChannel(InternetProtocolFamily.IPv4);
                        }
                    })
                    .localAddress(new InetSocketAddress(localAddress, groupPort))
                    .option(ChannelOption.IP_MULTICAST_IF, ni)
                    .option(ChannelOption.IP_MULTICAST_ADDR, InetAddress.getByName(localIp))
                    .option(ChannelOption.SO_REUSEADDR, true)
                    .option(ChannelOption.SO_RCVBUF, 2048 * 1024)
                    .option(ChannelOption.SO_SNDBUF, 1024 * 1024)
                    .handler(new ChannelInitializer<NioDatagramChannel>() {
                        @Override
                        protected void initChannel(NioDatagramChannel ch) throws Exception {
                            ChannelPipeline pipeline = ch.pipeline();
                            pipeline.addLast(new NioEventLoopGroup(), new UdpHandler());

                        }
                    });

            NioDatagramChannel channel = (NioDatagramChannel) bootstrap.bind(groupAddress.getPort()).sync().channel();
            channel.joinGroup(groupAddress, ni).sync();
            channel.closeFuture().await();
        } catch (SocketException e) {
            throw new RuntimeException(e);
        } catch (UnknownHostException e) {
            throw new RuntimeException(e);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            group.shutdownGracefully();
        }

    }

}

package com.demo.udp;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.socket.DatagramPacket;

public class UdpHandler extends SimpleChannelInboundHandler<DatagramPacket> {

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg) throws Exception {
        final ByteBuf buf = msg.content();
        int readableBytes = buf.readableBytes();
        byte[] msgData = new byte[readableBytes];
        buf.readBytes(msgData);

        String s = ByteUtil.bytesToHexString(msgData);
        System.out.println("接收到的数据 " + s);
    }
}

package com.demo.udp;


import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;

/**
 * Byte数组转换工具类
 */
public class ByteUtil {


    /**
     * 读取输入流中指定字节的长度
     * <p/>
     * 输入流
     *
     * @param length 指定长度
     * @return 指定长度的字节数组
     */
    public static byte[] readBytesFromTo(byte[] buffer, int from, int length) {
        byte[] sub = new byte[length];
        int cur = 0;
        for (int i = from; i < length + from; i++) {
            if (i >= buffer.length) {
                throw new ArrayIndexOutOfBoundsException("该报文长度不符合要求!");
            }
            sub[cur] = buffer[i];
            cur++;
        }
        return sub;
    }

    /**
     * 转换byte数组为int(小端)
     *
     * @return
     * @note 数组长度至少为4,按小端方式转换,即传入的bytes是小端的,按这个规律组织成int
     */
    public static int bytes2Int_LE(byte[] bytes) {
        if (bytes.length < 4) {
            return -1;
        }
        int iRst = (bytes[0] & 0xFF);
        iRst |= (bytes[1] & 0xFF) << 8;
        iRst |= (bytes[2] & 0xFF) << 16;
        iRst |= (bytes[3] & 0xFF) << 24;

        return iRst;
    }

    /**
     * 转换byte数组为Char(小端)
     *
     * @return
     * @note 数组长度至少为2,按小端方式转换
     */
    public static char bytes2Char_LE(byte[] bytes) {
        if (bytes.length < 2)
            return (char) -1;
        int iRst = (bytes[0] & 0xFF);
        iRst |= (bytes[1] & 0xFF) << 8;

        return (char) iRst;
    }

    /**
     * 转换byte数组为short(小端)
     *
     * @return
     * @note 数组长度至少为2,按小端方式转换
     */
    public static short littleByteToShort(byte[] data) {
        if (data.length != 2) {
            throw new UnsupportedOperationException("the byte length is not 2");
        }
        return ByteBuffer.allocate(data.length).put(data).getShort(0);
    }

    public static int bytes2Int(byte[] data) {
        if (data.length != 4) {
            throw new UnsupportedOperationException("the byte length is not 4");
        }
        return ByteBuffer.allocate(data.length).put(data).getInt(0);
    }

    /**
     * byte数组转换成16进制字符串
     */
    public static String bytesToHexString(byte[] bArray) {
        StringBuffer sb = new StringBuffer(bArray.length);
        String sTemp;
        for (int i = 0; i < bArray.length; i++) {
            sTemp = Integer.toHexString(0xFF & bArray[i]);
            if (sTemp.length() < 2) {
                sb.append(0);
            }
            sb.append(sTemp.toUpperCase());
        }
        return sb.toString();
    }

    /**
     * 16进制转换为字符串
     *
     * @param hex
     * @return
     */
    public static String hexStr2Str(String hex) {
        String hexStr = "";
        String str = "0123456789ABCDEF";
        for (int i = 0; i < hex.length(); i++) {
            String s = hex.substring(i, i + 1);
            if (s.equals("a") || s.equals("b") || s.equals("c") || s.equals("d") || s.equals("e") || s.equals("f")) {
                s = s.toUpperCase().substring(0, 1);
            }
            hexStr += s;
        }

        char[] hexs = hexStr.toCharArray();
        int length = (hexStr.length() / 2);
        byte[] bytes = new byte[length];
        int n;
        for (int i = 0; i < bytes.length; i++) {
            int position = i * 2;// 两个16进制字符 -> 1个byte数值
            n = str.indexOf(hexs[position]) * 16;
            n += str.indexOf(hexs[position + 1]);
            bytes[i] = (byte) (n & 0xff);
        }
        String name = "";
        try {
            name = new String(bytes, "GBK");
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return name;
    }

    /**
     * 字符串转换为Ascii
     *
     * @param value
     * @return
     */
    public static String stringToAscii(String value) {
        StringBuffer sbu = new StringBuffer();
        char[] chars = value.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            if (i != chars.length - 1) {
                sbu.append((int) chars[i]).append(",");
            } else {
                sbu.append((int) chars[i]);
            }
        }
        return sbu.toString();
    }

    /**
     * Ascii转换为字符串
     *
     * @param value
     * @return
     */
    public static String asciiToString(String value) {
        StringBuffer sbu = new StringBuffer();
        String[] chars = value.split(",");
        for (int i = 0; i < chars.length; i++) {
            sbu.append((char) Integer.parseInt(chars[i]));
        }
        return sbu.toString();
    }

    public static byte[] int2ByteLe(int res) {
        byte[] targets = new byte[4];

        targets[0] = (byte) (res & 0xff); // 最高位
        targets[1] = (byte) ((res >> 8) & 0xff);
        targets[2] = (byte) (res >> 16 & 0xff);
        targets[3] = (byte) (res >> 24 & 0xff);

        return targets;
    }

}


  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
以下是使用Netty实现UDP多线程接收数据的示例代码: ```java public class UdpServer { public static void main(String[] args) throws Exception { EventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap bootstrap = new Bootstrap(); bootstrap.group(group) .channel(NioDatagramChannel.class) .option(ChannelOption.SO_BROADCAST, true) .handler(new UdpServerHandler()); Channel channel = bootstrap.bind(8080).sync().channel(); channel.closeFuture().await(); } finally { group.shutdownGracefully(); } } private static class UdpServerHandler extends SimpleChannelInboundHandler<DatagramPacket> { private final ExecutorService executorService = Executors.newFixedThreadPool(10); @Override public void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) throws Exception { executorService.submit(() -> { ByteBuf buf = packet.copy().content(); byte[] req = new byte[buf.readableBytes()]; buf.readBytes(req); String message = new String(req, "UTF-8"); System.out.println("Received message: " + message); }); } } } ``` 在上面的代码中,我们使用了Netty的`NioDatagramChannel`来实现UDP服务器,同时设置了SO_BROADCAST选项以允许广播。我们还创建了一个多线程的`ExecutorService`来处理接收到的数据。当有数据包到达时,我们将其提交给线程池进行处理。 在`UdpServerHandler`中,我们重写了`channelRead0`方法来处理接收到的数据包。在这里,我们将数据包提交给线程池进行处理。注意,我们使用了`packet.copy().content()`来获取数据包的内容,并且将其转换为UTF-8编码的字符串进行处理。 最后,我们启动了UDP服务器并绑定到端口8080。当有数据包到达时,线程池将其处理并打印出来。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值