2021-04-18 11:31  阅读(89)
文章分类:Java 基础教程 文章标签:JavaJava 教程
©  原文作者:w3cschool 原文地址:https://www.w3cschool.cn/java/java-network-tcp-server.html

Java网络教程 - Java非阻塞套接字

使用非阻塞套接字通道,我们必须改变我们对执行顺序的思考方式。

服务器套接字通道

要创建选择器对象,请调用其open()静态方法。

    Selector selector = Selector.open();
    

ServerSocketChannel用于监听来自客户端的新连接请求。

调用其open()静态方法来创建一个ServerSocketChannel。

    ServerSocketChannel ssChannel = ServerSocketChannel.open();
    

默认情况下,服务器套接字通道或套接字通道是阻塞通道。要使其成为非阻塞通道,请调用以下方法。

    ssChannel.configureBlocking(false);
    

选择器

服务器套接字必须向选择器注册才能执行某些操作。

有四种操作,我们可以用选择器注册一个通道。

  • 使用SelectionKey.OP_CONNECT连接操作,可以在客户端为SocketChannel注册。选择器将通知有关连接操作进度。
  • 使用SelectionKey.OP_ACCEPT接受操作,可以在服务器上为ServerSocketChannel注册。当客户端请求新连接到达时,选择器将通知。
  • 使用SelectionKey.OP_READ读取操作,可以在客户端和服务器上为SocketChannel注册。选择器将在通道准备好读取某些数据时通知。
  • 使用SelectionKey.OP_WRITE进行写操作,可以在客户端和服务器上为SocketChannel注册。选择器将在通道准备好写入某些数据时通知。

例子

以下代码显示如何创建非阻塞套接字通道回显服务器程序。

    import java.net.InetAddress;
    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 Main {
      public static void main(String[] args) throws Exception {
        InetAddress hostIPAddress = InetAddress.getByName("localhost");
        int port = 19000;
        Selector selector = Selector.open();
        ServerSocketChannel ssChannel = ServerSocketChannel.open();
        ssChannel.configureBlocking(false);
        ssChannel.socket().bind(new InetSocketAddress(hostIPAddress, port));
        ssChannel.register(selector, SelectionKey.OP_ACCEPT);
        while (true) {
          if (selector.select() <= 0) {
            continue;
          }
          processReadySet(selector.selectedKeys());
        }
      }
      public static void processReadySet(Set readySet) throws Exception {
        Iterator iterator = readySet.iterator();
        while (iterator.hasNext()) {
          SelectionKey key = (SelectionKey) iterator.next();
          iterator.remove();
          if (key.isAcceptable()) {
            ServerSocketChannel ssChannel = (ServerSocketChannel) key.channel();
            SocketChannel sChannel = (SocketChannel) ssChannel.accept();
            sChannel.configureBlocking(false);
            sChannel.register(key.selector(), SelectionKey.OP_READ);
          }
          if (key.isReadable()) {
            String msg = processRead(key);
            if (msg.length() > 0) {
              SocketChannel sChannel = (SocketChannel) key.channel();
              ByteBuffer buffer = ByteBuffer.wrap(msg.getBytes());
              sChannel.write(buffer);
            }
          }
        }
      }
      public static String processRead(SelectionKey key) throws Exception {
        SocketChannel sChannel = (SocketChannel) key.channel();
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        int bytesCount = sChannel.read(buffer);
        if (bytesCount > 0) {
          buffer.flip();
          return new String(buffer.array());
        }
        return "NoMessage";
      }
    }
    

例2

非阻塞套接字通道回显客户端程序

    import java.io.BufferedReader;
    import java.io.InputStreamReader;
    import java.net.InetAddress;
    import java.net.InetSocketAddress;
    import java.nio.ByteBuffer;
    import java.nio.CharBuffer;
    import java.nio.channels.SelectionKey;
    import java.nio.channels.Selector;
    import java.nio.channels.SocketChannel;
    import java.nio.charset.Charset;
    import java.nio.charset.CharsetDecoder;
    import java.util.Iterator;
    import java.util.Set;
    /*from www.w3cschool.cn*/
    public class Main {
      static BufferedReader userInputReader = null;
    
      public static boolean processReadySet(Set readySet) throws Exception {
        Iterator iterator = readySet.iterator();
        while (iterator.hasNext()) {
          SelectionKey key = (SelectionKey)
           iterator.next();
          iterator.remove();
          if (key.isConnectable()) {
            boolean connected = processConnect(key);
            if (!connected) {
              return true; // Exit
            }
          }
          if (key.isReadable()) {
            String msg = processRead(key);
            System.out.println("[Server]: " + msg);
          }
          if (key.isWritable()) {
            System.out.print("Please enter a message(Bye to quit):");
            String msg = userInputReader.readLine();
            
            if (msg.equalsIgnoreCase("bye")) {
              return true; // Exit
            }
            SocketChannel sChannel = (SocketChannel) key.channel();
            ByteBuffer buffer = ByteBuffer.wrap(msg.getBytes());
            sChannel.write(buffer);
          }
        }
        return false; // Not done yet
      }
      public static boolean processConnect(SelectionKey key) throws Exception{
        SocketChannel channel = (SocketChannel) key.channel();
        while (channel.isConnectionPending()) {
          channel.finishConnect();
        }
        return true;
      }
      public static String processRead(SelectionKey key) throws Exception {
        SocketChannel sChannel = (SocketChannel) key.channel();
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        sChannel.read(buffer);
        buffer.flip();
        Charset charset = Charset.forName("UTF-8");
        CharsetDecoder decoder = charset.newDecoder();
        CharBuffer charBuffer = decoder.decode(buffer);
        String msg = charBuffer.toString();
        return msg;
      }
      public static void main(String[] args) throws Exception {
        InetAddress serverIPAddress = InetAddress.getByName("localhost");
        int port = 19000;
        InetSocketAddress serverAddress = new InetSocketAddress(
            serverIPAddress, port);
        Selector selector = Selector.open();
        SocketChannel channel = SocketChannel.open();
        channel.configureBlocking(false);
        channel.connect(serverAddress);
        int operations = SelectionKey.OP_CONNECT | SelectionKey.OP_READ
            | SelectionKey.OP_WRITE;
        channel.register(selector, operations);
    
        userInputReader = new BufferedReader(new InputStreamReader(System.in));
        while (true) {
          if (selector.select() > 0) {
            boolean doneStatus = processReadySet(selector.selectedKeys());
            if (doneStatus) {
              break;
            }
          }
        }
        channel.close();
      }
    }
    
点赞(0)
版权归原创作者所有,任何形式转载请联系作者; Java 技术驿站 >> Java 非阻塞套接字
上一篇
Java URL
下一篇
Java 异步套接字通道