天天看點

Java NIO UDP發送接收資料

Java的NIO包中,有一個專門用于發送UDP資料包的類:DatagramChannel,UDP是一種無連接配接的網絡協定,
一般用于發送一些準确度要求不太高的資料等。
           

完整的服務端程式如下:

public class StatisticsServer {
    //每次發送接收的資料包大小
    private final int MAX_BUFF_SIZE =  * ;
    //服務端監聽端口,用戶端也通過該端口發送資料
    private int port;
    private DatagramChannel channel;
    private Selector selector;

    private ScheduledExecutorService es = Executors.newScheduledThreadPool();

    public void init() throws IOException {
        //建立通道和選擇器
        selector = Selector.open();
        channel = DatagramChannel.open();
        //設定為非阻塞模式
        channel.configureBlocking(false);
        channel.socket().bind(new InetSocketAddress(port));
        //将通道注冊至selector,監聽隻讀消息(此時服務端隻能讀資料,無法寫資料)
        channel.register(selector, SelectionKey.OP_READ);

        //使用線程的方式,保證服務端持續等待接收用戶端資料
        es.scheduleWithFixedDelay(new Runnable() {
            @Override
            public void run() {
                try {
                    while(selector.select() > ) {
                        Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
                        while(iterator.hasNext()) {
                            SelectionKey key = iterator.next();
                            try {
                                iterator.remove();
                                if(key.isReadable()) {
                                    //接收資料
                                    doReceive(key);
                                }
                            } catch (Exception e) {
                                logger.error("SelectionKey receive exception", e);
                                try {
                                    if (key != null) {
                                        key.cancel();
                                        key.channel().close();
                                    }
                                } catch (ClosedChannelException cex) {
                                    logger.error("Close channel exception", cex);
                                }
                            }
                        }
                    }
                } catch (IOException e) {
                    logger.error("selector.select exception", e);
                }
            }
        }, L, L, TimeUnit.MINUTES);

    }

    //處理接收到的資料
    private void doReceive(SelectionKey key) throws IOException {
        String content = "";
        DatagramChannel sc = (DatagramChannel) key.channel();
        ByteBuffer buffer = ByteBuffer.allocate(MAX_BUFF_SIZE);
        buffer.clear();
        sc.receive(buffer);
        buffer.flip();
        while(buffer.hasRemaining()) {
            byte[] buf = new byte[buffer.limit()];
            buffer.get(buf);
            content += new String(buf);
        }
        buffer.clear();
        logger.debug("receive content="+content);
        if(StringUtils.isNotBlank(content)) {
            doSave(content);
        }
    }
 }
           

用戶端發送完整例子如下:

DatagramChannel channel = DatagramChannel.open();

        StringBuilder sb = new StringBuilder();
        sb.append("2017-03-09 12:30:00;")
                .append("aaa")
                .append("testapp;")
                .append("test.do;")
                .append("param=hello;")
                .append("test;")
                .append("100;")
                .append("1");
        ByteBuffer buffer = ByteBuffer.allocate();
        buffer.clear();
        buffer.put(sb.toString().getBytes());
        buffer.flip();
        //此處IP為服務端IP位址,端口和服務端的端口一緻
        int n = channel.send(buffer, new InetSocketAddress("127.0.0.1", ));
        System.out.println(n);
        //每次資料發送完畢之後,一定要調用close方法,來關閉占用的udp端口,否則程式不結束,端口不會釋放
        channel.close();