• ServerSocketChannel

  • ServerSocketChannel作用?就是专职干什么的?

        1、监听新进来的TCP链接通道,

        2、创建新的SocketChannel

  • ServerSocketChannel 不具备 什么能力

    ServerSocketChannel并不能进行数据传输的能力

  • 如何创建ServerSocketChannel实例

    ServerSocketChannel socketChannel =ServerSocketChannel.open();

    该对象关联了一个未绑定ServerSocket的通道,

  • 为ServerSocketChannel绑定监听端口号

    JDK1.7前,需要调用ServerSocketChannel的socket方法,再调用bind()来进行关联

    JDK1.7后,就可以直接调用ServerSocketChannel的bind()来进行端口绑定了。

  • ServerSocketChannel如何监听新进来的连接

    通过 ServerSocketChannel.accept() 方法监听新进来的连接。

    ServerSocketChannel 默认是 阻塞模式,可以查看JDK源码

    如下,所示:

Java NIO 之 ServerSocketChannel 与 SocketChannel_第1张图片

Java NIO 之 ServerSocketChannel 与 SocketChannel_第2张图片

Java NIO 之 ServerSocketChannel 与 SocketChannel_第3张图片


通过ServerSocketChannel.configureBlocking(true)来设定阻塞模式

 1、在阻塞模式下,

    如果有新的连接进来,那么accept()方法返回的是一个包含新进来的连接的SocketChannel,

        如果没有新的连接,那么accept()方法,就会一直阻塞在这里,直到有的新连接进来

   

 2、在非阻塞模式下ServerSocketChannel. configureBlocking(false)

    如果有连接进来,那么accept()方法返回的是一个包含新进来的连接的SocketChannel

    如果没有新的连接,那么accept()方法会立即返回null


 3、阻塞模式与非阻塞模式的根本区别?

    其实,就是在没有新的连接的情况下,如何处理的?不返回,一直等待的话,就是阻塞;

    如果立即返回的话,就是非阻塞了。

    

  • SocketChannel

  • 创建SocketChannel的方式?

    方式一:在客户端创建

        SocketChannel socketChannel = SocketChannel.open();

    方式二:在服务器端创建

        ServerSocketChannel接受一个连接请求后得到,如

        SocketChannel socketChannel = serverSocketChannel.accept();

  • 将管道中的数据读到缓存里,用的是socketChannel的read方法

        int read = socketChannel.read(sizeBuffer);

  • 将缓存里的数据写到管道中,用的是socketChannel的write方法

        socketChannel.write(sizeBuffer);

 

例子如下:

服务端:

package xingej.channel;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;

public class ServerSocketChannelTest {
    public void initChannel() throws IOException {
        //服务器端,通过open方法,来创建ServerSocketChannel
        //注意,此时,服务器端,还没有进行绑定端口呢
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

        //设置为非阻塞模式
//        serverSocketChannel.configureBlocking(false);
        //绑定端口号
        //JDK1.7版本之后的写法
        serverSocketChannel.bind(new InetSocketAddress(8081));
        //JDK1.7版本之前的写法
//        serverSocketChannel.socket().bind(new InetSocketAddress(8081));

        //创建字节缓存区
        //缓存区的大小是1024字节,这个可以自己调试,如改成64,128....
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

        while (true) {
            System.out.println("-------服务器端-----开始接收-----客户端的连接---------");
            //在服务器端,接收客户端的链接,如果存在客户端的话,就返回一个
            //SocketChannel对象
            //如果是阻塞模式的话,没有新的链接进来,就会阻塞在这里,否则,往下执行
            //如果是非阻塞模式的话,没有新的链接进来,就会立马返回一个null,程序不会阻塞在这里,
            //会立马往下进行的
            SocketChannel socketChannel = serverSocketChannel.accept();
            if (null != socketChannel) {
                while (true) {
                    //清楚缓存区的数据,可以接收新的数据
                    byteBuffer.clear();

                    //将管道socketChannel的数据读取到 缓存byteBuffer里
                    //readSize 表示 读取的字节数
                    int readSize = socketChannel.read(byteBuffer);
                    if (readSize == -1) {
                        break;
                    }
                    //再从 字节缓存里,进行其他 业务逻辑操作,\
                    // 注意,这里的缓存区使用的字节类型
                    // 因此,如果需要其他类型的话,需要进行转换
                    System.out.println(new String(byteBuffer.array()));
                }
            }

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws IOException {
        new ServerSocketChannelTest().initChannel();
    }
}


 客户端如下:

package xingej.channel;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;

public class SocketChannelTest {

    public void connectServer() throws IOException{
        // 创建一个 SocketChannel对象,
        // 请注意,并没有进行 链接服务器端哦
        SocketChannel socketChannel = SocketChannel.open();

        //开始链接服务器端
        socketChannel.connect(new InetSocketAddress("localhost", 8081));

        //在客户端创建 字节缓存区
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

        String msg = "\nhello, nio, hello ,spark, hello ,hadoop, flume, mesos, marathon, netty, mina, stream, inputstream, outputstream \n" +
                "hello, nio, hello ,spark, hello ,hadoop, flume, mesos, marathon, netty, mina, stream, inputstream, outputstream \n" +
                "hello, nio, hello ,spark, hello ,hadoop, flume, mesos, marathon, netty, mina, stream, inputstream, outputstream 北京\n";

        //往字节缓存区,添加数据
        byteBuffer.put(msg.getBytes());
        // 针对是更新limit值,将此值更新为position了,用于接下来的读操作
        byteBuffer.flip();
        while(byteBuffer.hasRemaining()) {
            //将字节缓存里的数据,写到管道中去
            socketChannel.write(byteBuffer);
        }

        socketChannel.close();
    }

    public static void main(String[] args) throws IOException{
        new SocketChannelTest().connectServer();
    }
}


启动方式:

先启动服务器端,然后再启动客户端