频道栏目
首页 > 程序开发 > 软件开发 > Java > 正文
java NIO socket编程简介
2017-02-08 22:24:00         来源:wsdchigh的博客  
收藏   我要投稿

针对于BIO的弊端,在java后续版本中推出了NIO,在此之前,网络通信方面很少使用java的BIO,有更好的为何不用。N可以理解为new的意思,新的io,在NIO里面可以选择不阻塞,默认是阻塞的。NIO的三大 核心channel,buffer,selector,通道用于传输数据,类似于流,buffer存储数据的缓冲,selector选择器。对于它们的工作,我是这么认为的,channerl注册selector,channel可以注册读,写等多个,selector通过遍历里面的元素,获取数据,数据的都和 写通过buffer来实现,传输时通过channel,在遍历的时候,取出数据,或者存入数据,如果什么也没有或者什么也没有写入,那么就什么也没有,这样就可以实现一个线程控制多个socket。当然大型服务器是不可能只使用一个selector的,通常一个网段使用一个或者多个selector,所以说网络方面比较复杂,能够使用netty等框架,就不要自己去实现一个框架来实现自己的功能,当然大牛就是写框架的。用的少,不代表不要精通,这是通往大牛的一步,要带着理想学习。

客户端 仅是简单的发送
package com.wsdc.socket;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.concurrent.TimeUnit;

public class Client {
    public static void main(String[] args) {
        SocketChannel sc = null;

        try {
            sc = SocketChannel.open();

            sc.configureBlocking(false);

            sc.connect(new InetSocketAddress("127.0.0.1", 9999));

            if(sc.finishConnect()){
                ByteBuffer bb = ByteBuffer.allocate(1024);

                String str = "少年壮志不言愁";

                while(true){
                    bb.clear();

                    TimeUnit.SECONDS.sleep(1);

                    bb.put(str.getBytes());

                    bb.flip();

                    sc.write(bb);

                    System.out.println("发送数据");
                }
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}

 

服务端 java对于通信的操作均是socket,无论采取那种方式,均是可以 读取数据的,也就是说,用BIO的方式发送,用NIO的方式接收,这是完全没有问题的,只不过是面向socket的不同方向而已,本质均是从 socket中读取和写入数据

 

package com.wsdc.socket;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.concurrent.TimeUnit;

/**
 * 
 * @author ASUS
 * 只要是socket通信  无论是使用io还是nio均可以使用
 * 
 * io或者nio来接收  实现混合使用  当然这里指的是服务端和客户端可以使用不同
 * 
 * 的策略  对于同一侧应该要使用同一种类型
 * 
 * 底层实现的是TCP/IP,无论是io还是nio均为对底层操作
 * 
 * 数据并不会发生改变  对于服务器而言通常需要使用nio  对付
 * 
 * 客户端使用io或者nio   还有aio异步io
 */
public class Server {
    public static void main(String[] args) {
        //oldMethod();

        //newMethodBlock();

        newMethodUnBlock();

        //selector();
    }

    //阻塞的接收方法  
    public static void newMethodBlock(){
        ServerSocketChannel ssc = null;

        SocketChannel sc = null;

        try {
            ssc = ServerSocketChannel.open();

            ssc.socket().bind(new InetSocketAddress(9999));

            sc = ssc.accept();

            ByteBuffer bb = ByteBuffer.allocate(1024);

            while(true){
                if(sc == null){
                    continue;
                }

                sc.read(bb);

                bb.flip();

                System.out.println("接收数据");

                System.out.println(new String(bb.array()));
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally{
            if(sc != null){
                try {
                    sc.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }

            if(ssc != null){
                try {
                    ssc.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }

    //nio非阻塞接收方法   即注册接收器
    public static void newMethodUnBlock(){
        ServerSocketChannel ssc = null;

        Selector selector = null;

        ByteArrayOutputStream bos = null;

        try {
            bos = new ByteArrayOutputStream();

            ssc = ServerSocketChannel.open();

            ssc.socket().bind(new InetSocketAddress(9999));

            ssc.configureBlocking(false);

            selector = selector.open();

            ssc.register(selector, SelectionKey.OP_ACCEPT);

            Iterator it = null;

            SelectionKey key = null;

            while(true){
                if(selector.select(3000) == 0){
                    System.out.println("尚未连接");

                    continue;
                }

                it = selector.selectedKeys().iterator();

                while(it.hasNext()){
                    key = it.next();

                    Thread.sleep(500);

                    if(key.isAcceptable()){
                        /**
                         * 这里表示ssc处于可以连接状态   
                         * 
                         * ssc设置为非阻塞状态,一旦客户端处于连接 这里就会触发
                         * 
                         * 一旦有新的客户端连接  这里的sc才会有返回值
                         * 
                         * 否者会一直为空   即后面的代码就没有什么用处
                         * 
                         * 注意这里不能注册Accept  只能注册read和write
                         * 
                         * 可以注册多个   channel在关闭的时候会自动解除注册
                         */
                        ssc = (ServerSocketChannel) key.channel();

                        SocketChannel sc = ssc.accept();

                        sc.configureBlocking(false);

                        sc.register(key.selector(), SelectionKey.OP_READ|SelectionKey.OP_WRITE,ByteBuffer.allocateDirect(1024));



                    }

                    //这里是针对于连接生成的sc具备的读状态
                    if(key.isReadable()){
                        SocketChannel sc1 = (SocketChannel) key.channel();

                        ByteBuffer bb = (ByteBuffer) key.attachment();

                        int len = sc1.read(bb);

                        if(len == -1){
                            sc1.close();
                        }

                        bb.flip();

                        while(bb.hasRemaining()){
                            bos.write(bb.get());
                        }

                        System.out.println(new String(bos.toByteArray(),0,len));

                        bos.reset();

                        bb.clear();

                    }

                    if(key.isWritable()){
                        System.out.println("写状态");
                    }

                    if(key.isConnectable()){
                        System.out.println("连接状态");
                    }
                    /**
                     * 此处是将处理过的数据移除
                     * 
                     * 下一次的循环会再次将注册的通道通道添加
                     * 
                     * 但是不会自动移除  需要手动移除
                     */
                    it.remove();

                }
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            if(ssc != null){
                try {
                    ssc.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

            }
            if(selector != null){
                try {
                    selector.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }


    //io的接收方法    
    public static void oldMethod(){
        ServerSocket ss = null;

        Socket socket = null;

        InputStream is = null;

        try {
            ss = new ServerSocket(9999);

            socket = ss.accept();

            is = socket.getInputStream();

            int len = 0;

            byte[] data = new byte[1024];

            while((len = is.read(data)) != -1){
                System.out.println(new String(data,0,len));
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

}

 

需要注意的是 如果没有设置不阻塞的话,也就是阻塞,是会在accept处阻塞,如果设置了不阻塞,会直接返回,如果没有连接,那么就返回null 坚决不会阻塞

 

点击复制链接 与好友分享!回本站首页
相关TAG标签 javaNIO socket编程
上一篇:java BIO socket的简单使用
下一篇:java.lang.NoSuchMethodError: javax.persistence.OneToOne.orphanRemoval()
相关文章
图文推荐
点击排行

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站