zoukankan      html  css  js  c++  java
  • NIO之三Socket通道

    1 Socket通道

      所有的socket通道类(DatagramChannel、SocketChannel和ServerSocketChannel)都继承了位于java.nio.channels.spi包中的AbstractSelectableChannel。请注意DatagramChannel和SocketChannel实现定义读和写功能的接口而ServerSocketChannel不实现。ServerSocketChannel负责监听传入的连接和创建新的SocketChannel对象,它本身从不传输数据。

      全部socket通道类(DatagramChannel、SocketChannel和ServerSocketChannel)在被实例化时都会创建一个对等socket对象。这些是我们所熟悉的来自java.net的类(Socket、ServerSocket和DatagramSocket),它们已经被更新以识别通道。对等socket可以通过调用socket( )方法从一个通道上获取。此外,这三个java.net类现在都有getChannel( )方法。Socket通道将与通信协议相关的操作委托给相应的socket对象。socket的方法看起来好像在通道类中重复了一遍,但实际上通道类上的方法会有一些新的或者不同的行为

    2、 ServerSocketChannel

      ServerSocketChannel 的几个方法,ServerSocketChannel是一个基于通道的socket监听器。它同我们所熟悉的java.net.ServerSocket执行相同的基本任务,不过它增加了通道语义,因此能够在非阻塞模式下运行。由于ServerSocketChannel没有bind()方法,因此有必要取出对等的socket并使用它来绑定到一个端口以开始监听连接。我们也是使用对等ServerSocket的API来根据需要设置其他的socket选项。

      同它的对等体java.net.ServerSocket一样,ServerSocketChannel也有accept( )方法。一旦您创建了一个ServerSocketChannel并用对等socket绑定了它,然后您就可以在其中一个上调用accept()。如果您选择在ServerSocket上调用accept( )方法,那么它会同任何其他的ServerSocket表现一样的行为:总是阻塞并返回一个java.net.Socket对象。如果您选择在ServerSocketChannel上调用accept( )方法则会返回SocketChannel类型的对象,返回的对象能够在非阻塞模式下运行。

    public abstract class ServerSocketChannel extends AbstractSelectableChannel
      {
          public static ServerSocketChannel open() throws IOException;
          public abstract ServerSocket socket();
          public abstract SocketChannel accept()throws IOException;
          public final int validOps();
      }
    

      如果ServerSocketChannel以非阻塞模式被调用,当没有传入连接在等待时,ServerSocketChannel.accept( )会立即返回null。正是这种检查连接而不阻塞的能力实现了可伸缩性并降低了复杂性。可选择性也因此得到实现。我们可以使用一个选择器实例来注册一个ServerSocketChannel对象以实现新连接到达时自动通知的功能。以下代码演示了如何使用一个非阻塞的accept( )方法:

    2.1打开 ServerSocketChannel

      通过调用 ServerSocketChannel.open() 方法来打开ServerSocketChannel.如:

    ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
    2.2、监听新进来的连接

      通过 ServerSocketChannel.accept() 方法监听新进来的连接。当 accept()方法返回的时候,它返回一个包含新进来的连接的 SocketChannel。因此, accept()方法会一直阻塞到有新连接到达。

    2.2、监听新进来的连接设置为非阻塞

      ServerSocketChannel可以设置成非阻塞模式。在非阻塞模式下,accept() 方法会立刻返回,如果还没有新进来的连接,返回的将是null。 因此,需要检查返回的SocketChannel是否是null.如:

            ServerSocketChannel ssc = ServerSocketChannel.open();
            ssc.socket().bind(new InetSocketAddress(port));
            ssc.configureBlocking(false);
            while (true) {
                System.out.println("Waiting for connections");
                SocketChannel sc = ssc.accept();
                if(sc != null) {
                    
                }
    

      

    三、SocketChannel

    Java NIO中的SocketChannel是一个连接到TCP网络套接字的通道。可以通过以下2种方式创建SocketChannel:

    • 打开一个SocketChannel并连接到互联网上的某台服务器。
    • 一个新连接到达ServerSocketChannel时,会创建一个SocketChannel。
    3.1、打开 SocketChannel

    下面是SocketChannel的打开方式:

    SocketChannel socketChannel = SocketChannel.open();
    socketChannel.connect(new InetSocketAddress("http://127.0.0.1", 80)); 
    3.2、从 SocketChannel 读取数据

    要从SocketChannel中读取数据,调用一个read()的方法之一。以下是例子:

    ByteBuffer buf = ByteBuffer.allocate(48);
    int bytesRead = socketChannel.read(buf);
    

    首先,分配一个Buffer。从SocketChannel读取到的数据将会放到这个Buffer中,调用SocketChannel.read(),该方法将数据从SocketChannel 读到Buffer中。read()方法返回的int值表示读了多少字节进Buffer里。如果返回的是-1,表示已经读到了流的末尾(连接关闭了)。 

    3.3、写入 SocketChannel

    写数据到SocketChannel用的是SocketChannel.write()方法,该方法以一个Buffer作为参数。示例如下:

    String newData = "New String to write to file..." + System.currentTimeMillis();
    ByteBuffer buf = ByteBuffer.allocate(48);
    buf.clear();
    buf.put(newData.getBytes());
    buf.flip();
    while(buf.hasRemaining()) {
        channel.write(buf);
    }
    

      注意SocketChannel.write()方法的调用是在一个while循环中的。Write()方法无法保证能写多少字节到SocketChannel。所以,我们重复调用write()直到Buffer没有要写的字节为止。

    3.4.connect()

    如果SocketChannel在非阻塞模式下,此时调用connect(),该方法可能在连接建立之前就返回了。为了确定连接是否建立,可以调用finishConnect()的方法。像这样:

    socketChannel.configureBlocking(false);
    socketChannel.connect(new InetSocketAddress("http://jenkov.com", 80));
     
    while(! socketChannel.finishConnect() ){
        //wait, or do something else...
    }
    

      

     

  • 相关阅读:
    第一章 重构
    Android View的事件分发
    java.lang.NoSuchMethodError: android.view.View.setBackground
    handler消息机制
    魅族手机Listview下拉出现hold字样的奇葩问题解决方案
    数据结构--树,二叉树
    数据结构之栈和队列
    设计模式--六大原则
    ListView上下线添加
    Python 入门(七)函数
  • 原文地址:https://www.cnblogs.com/sharing-java/p/10802152.html
Copyright © 2011-2022 走看看