upd组播使用nio接收 有序

最近客户需求很苛刻,要求1ms接收到 udp 1条,极限下2微秒1条记录,还不能大量丢包

传统io个人感觉应该也能应付过来,但是还是选用nio ,因为我们是接收端,所以代码很简单。不管是bio(传统io)还是nio其实都是使用一个线程一直处于while循环状态,一直监听

我们还需要处理业务,同时也要保持接收过来的udp报文有序存储,所以需要使用队列

package com.hjkj.udp.cyc.formal;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.*;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.concurrent.BlockingQueue;

/**
 * @author cyc
 * @version 2020-9-28
 *
 * nio流接收udp 数据 并且把数据存放在队列中
 *
 * (生产者)
 * */
public class NioUdpServer implements Runnable{

    private static Logger logger = LoggerFactory.getLogger(NioUdpServer.class);
    //私有队列(队列设置10w条数据顶峰.超过这个值就报错,如果不想报错,就继续扩大队列// )
    private BlockingQueue<byte[]> queue;
    private int count=0;
    //通道
    private DatagramChannel datagramChannel;
    //轮询器
    private Selector selector;

    public NioUdpServer(BlockingQueue<byte[]> queue) {
        this.queue = queue;
    }

    //接收方法
    @Override
    public void run(){
        //ipv4组协议
        try {
            datagramChannel=DatagramChannel.open(StandardProtocolFamily.INET);
            datagramChannel.configureBlocking(false);
            datagramChannel.setOption(StandardSocketOptions.SO_REUSEADDR, true).bind(new InetSocketAddress(18465));
            NetworkInterface networkInterface = NetworkInterface.getByInetAddress(InetAddress.getByName("192.168.1.206"));
            /*添加到组播*/
            datagramChannel.join(InetAddress.getByName("230.1.1.61"), networkInterface);

            //打开轮询器
            selector = Selector.open();

            datagramChannel.register(selector, SelectionKey.OP_READ);

            while (selector.select() > 0){
                Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
                /*缓冲区大小*/
                ByteBuffer byteBuffer = ByteBuffer.allocate(1500);
                while(iterator.hasNext()){
                    SelectionKey selectionKey = iterator.next();

                    // 可读事件,有数据到来
                    if (selectionKey.isReadable()) {
datagramChannel.receive(byteBuffer);
byteBuffer.flip();
SimpleDateFormat format
= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS"); System.err.println("接收到的数量:"+(++count)+"收到客户端消息:{}"+"时间:"+ format.format(new Date()));
              //存入到队列 queue.put(byteBuffer.array());
byteBuffer.clear(); } } iterator.remove(); } }
catch (SocketException e) { e.printStackTrace(); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } }

下面是数据处理类,由于公司的业务保密,所以具体的业务代码就不写了

package com.hjkj.udp.cyc.formal;

import com.hjkj.udp.cyc.entity.T_Monitor_Manager;
import com.hjkj.udp.cyc.utils.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigInteger;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.stream.Collectors;

/**
 * @author cyc
 * @version 2020-9-28
 * udp数据处理类
 */
@Slf4j
public class DataServer implements Runnable {

    private static Logger logger = LoggerFactory.getLogger(DataServer.class);

    private BlockingQueue<byte[]> queue;

    private BlockingQueue<Map<String, Object>> blockcount;

    private RedisUtil objRedisTemplateUtils;

    private List<T_Monitor_Manager> lstMonitorItems;

    public DataServer(BlockingQueue<byte[]> queue, BlockingQueue<Map<String, Object>> blockcount, RedisUtil objRedisTemplateUtils, List<T_Monitor_Manager> listMonitorItems) {
        this.queue = queue;
        this.blockcount = blockcount;
        this.objRedisTemplateUtils = objRedisTemplateUtils;
        this.lstMonitorItems = listMonitorItems;
    }

    @Override
    public void run() {
      /*  while (true) {
            try {
                Thread.sleep(0);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (queue.size() > 0) {*/
                read();
       /*     }
        }*/
    }

    public void read() {
      
byte[] buff = queue.poll(); ....省略业务代码
    Map map=new HashMap();
    blockcount.put(map);
  }
}

 

posted @ 2020-10-09 13:52  幽灵中的野孩子  阅读(362)  评论(0编辑  收藏  举报