辛星2018年nio教程第七篇:SocketChannel与ServerSocketChannel

先打个小广告,关注辛星教程,我的微信号xinxing0913,该项目源码所在的github地址: https://github.com/xinxing0913/xinxing-nio-guide。

前面我们介绍的操作都是对于本地文件的操作,接下来我们就要进行网络相关的操作了。这里我们经常使用的两个Channel是SocketChannel与ServerSocketChannel。

SocketChannel是用于TCP网络连接的套接字接口,它一般用来作为客户端的套接字,它有点类似于java中的Socket类。我们使用它的一般套路是:

SocketChannel channel = SocketChannel.open();
channel.connect(xxx);

我们可以用它的read方法来读取数据,我们也可以用它的write方法来写入数据,我们可以用它的configureBlocking(false)方法来设置为非阻塞模式。不过需要说明的是,由于真实场景下读取数据可能不是一次性能完成,因此可能需要在一个循环中进行读取。

ServerSocketChannel是用于监听TCP连接的通道,它类似于java网络编程中的ServerSocket,它的一般使用道路是:

ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(xxx);

while (true) {
    SocketChannel client = serverSocketChannel.accept();
    // 其他操作
    client.close(); 
 }

这里我们首先调用它的open方法来打开一个通道,然后我们调用其bind()方法来绑定到某个地址上,然后我们通过accept()方法来每次获取一个客户端的连接,别忘记在操作完客户端之后要关闭。

我们接下来就来编写一个nio的客户端和服务端通信的范例把,首先是client代码的范例:

/**
 * 基于nio实现的非阻塞客户端
 */
public class Demo9 {
    public static void main(String[] args) throws Exception{
        SocketChannel socketChannel = SocketChannel.open();
        socketChannel.configureBlocking(false); // 设置为非阻塞
        socketChannel.connect(new InetSocketAddress(8080));
        socketChannel.finishConnect(); // 等待连接完成

        // 向服务端发送一段文本
        byte[] bytes = "hello 辛星".getBytes();
        ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
        socketChannel.write(byteBuffer);

        // 最多只接受服务端的1024个字节
        ByteBuffer responseBuffer = ByteBuffer.allocate(1024);
        socketChannel.read(responseBuffer);
        System.out.println("服务端响应的数据:" + new String(responseBuffer.array()));
    }
}

需要特殊说明的是,我们调用了finishConnect()方法来等待连接完成,然后才发的消息,如果连接未完成就发消息的话,可能会抛出NotYetConnectedException异常。

然后我们来编写一个nio的服务端的范例把,如下所示:

/**
 * 基于nio实现的非阻塞服务端
 */
public class Demo10 {
    private static final byte[] bytes = "received !!".getBytes();

    public static void main(String[] args) throws Exception {
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.bind(new InetSocketAddress(8080));
        serverSocketChannel.configureBlocking(false);

        System.out.println("服务端已启动,开始接受客户端连接...");

        while (true) {
            SocketChannel socketChannel = serverSocketChannel.accept();
            if (!Objects.isNull(socketChannel)) {
                // 最多只接受客户端的1024个字节
                ByteBuffer requestBuffer = ByteBuffer.allocate(1024);
                socketChannel.read(requestBuffer);
                System.out.println("客户端输入的内容:" + new String(requestBuffer.array()));

                // 给客户端写入数据,然后关闭连接
                // 发送给客户端的文本信息
                ByteBuffer responseBuffer = ByteBuffer.wrap(bytes);
                socketChannel.write(responseBuffer);
                socketChannel.close();
            }
        }
    }
}

然后我们首先启动服务器,我们看到如下所示的效果:


image.png

然后我们启动客户端,我们会看到如下效果:


image.png

然后我们的服务端就会收到一次处理连接的信息,如下所示:


image.png

对于基于TCP的通信操作,我们就介绍到这里啦。

你可能感兴趣的:(辛星2018年nio教程第七篇:SocketChannel与ServerSocketChannel)