五、[ Java NIO ] server和client完整通信实践案例

服务器:

我们通过调用静态open方法创建Selector对象。然后,我们还通过调用其静态open方法(特别是ServerSocketChannel实例)来创建通道。
这是因为ServerSocketChannel是可选择的,并且适合于面向流的侦听套接字。

然后将其绑定到我们选择的端口。记得我们前面说过,在将可选通道注册到选择器之前,必须首先将其设置为非阻塞模式。接下来我们做这个,然后把通道注册到选择器。

Java NIO使用面向缓冲区的模型,而不是面向流的模型。所以套接字通信通常是通过读写缓冲区来进行的。

因此,我们创建一个新的ByteBuffer,服务器将从这个ByteBuffer写入和读取数据。我们将它初始化为256字节,它只是一个任意值,取决于我们计划来回传输多少数据。

ServerSocketChannel只能处理ACCEPT操作。当我们接受来自客户机的连接时,我们获得一个SocketChannel对象,我们可以在该对象上执行读写操作。我们将其设置为非阻塞模式,并将其注册为读取操作。

当我们想要写入正在从中读取的缓冲区时,必须调用flip()方法。

package nio.net_demo;

import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
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.Set;

public class NIOServer {

    private static final String POISON_PILL = "POISON_PILL";

    public static void main(String[] args) throws IOException {
        Selector selector = Selector.open();
        ServerSocketChannel serverSocket = ServerSocketChannel.open();
        serverSocket.bind(new InetSocketAddress("localhost", 5454));
        serverSocket.configureBlocking(false);
        serverSocket.register(selector, SelectionKey.OP_ACCEPT);
        ByteBuffer buffer = ByteBuffer.allocate(256);

        while (true) {
            selector.select();
            Set<SelectionKey> selectedKeys = selector.selectedKeys();
            Iterator<SelectionKey> iter = selectedKeys.iterator();
            while (iter.hasNext()) {

                SelectionKey key = iter.next();

                if (key.isAcceptable()) {
                    register(selector, serverSocket);
                }

                if (key.isReadable()) {
                    answerWithEcho(buffer, key);
                }
                iter.remove();
            }
        }
    }

    private static void answerWithEcho(ByteBuffer buffer, SelectionKey key)
            throws IOException {

        SocketChannel client = (SocketChannel) key.channel();
        client.read(buffer);
        if (new String(buffer.array()).trim().equals(POISON_PILL)) {
            client.close();
            System.out.println("Not accepting client messages anymore");
        }

        buffer.flip();
        client.write(buffer);
        buffer.clear();
    }

    private static void register(Selector selector, ServerSocketChannel serverSocket)
            throws IOException {
        SocketChannel client = serverSocket.accept();
        client.configureBlocking(false);
        client.register(selector, SelectionKey.OP_READ);
    }

    public static Process start() throws IOException, InterruptedException {
        String javaHome = System.getProperty("java.home");
        String javaBin = javaHome + File.separator + "bin" + File.separator + "java";
        String classpath = System.getProperty("java.class.path");
        String className = NIOServer.class.getCanonicalName();

        ProcessBuilder builder = new ProcessBuilder(javaBin, "-cp", classpath, className);

        return builder.start();
    }
}

客户端:我们使用一个单例模式在start静态方法中实例化它。我们从这个方法调用私有构造函数。在私有构造函数中,我们在绑定服务器通道的同一端口上打开连接,并且仍然在同一主机上。然后,我们创建一个可以写入和读取的缓冲区。最后,我们有一个sendMessage方法,它读取将传递给它的任何字符串包装到字节缓冲区中,字节缓冲区通过通道传输到服务器。
然后从客户端通道读取,以获取服务器发送的消息。

package nio.net_demo;

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

public class NIOClient {
    private static SocketChannel client;
    private static ByteBuffer buffer;
    private static NIOClient instance;

    public static NIOClient start() {
        if (instance == null)
            instance = new NIOClient();

        return instance;
    }

    public static void stop() throws IOException {
        client.close();
        buffer = null;
    }

    private NIOClient() {
        try {
            client = SocketChannel.open(new InetSocketAddress("localhost", 5454));
            buffer = ByteBuffer.allocate(256);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public String sendMessage(String msg) {
        buffer = ByteBuffer.wrap(msg.getBytes());
        String response = null;
        try {
            client.write(buffer);
            buffer.clear();
            client.read(buffer);
            response = new String(buffer.array()).trim();
            System.out.println("response=" + response);
            buffer.clear();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return response;

    }
}

测试代码:

package nio.net_demo;

import java.io.IOException;

public class MianTest {

    public static void main(String[] args) throws IOException, InterruptedException {
        Process nioServer = NIOServer.start();
        NIOClient nioClient = NIOClient.start();

        nioClient.sendMessage("2323232424");
//        nioServer.
    }
}

 

 

 

 

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值