socket通道

来源:互联网 发布:天风证券 数据库新浪 编辑:程序博客网 时间:2022/08/11 16:58

socket通道基础

        sokcet通道类可以运行非阻塞模式并且是可选择的。这两个性能可以激活大程序巨大的可伸缩性和灵活性。

        所有的socket通道类(DatagramChannel,SocketChannel和ServerSocketChannel)都继承了java.nio.channels.spi.AbstractSelectableChannel。

        DatagramChannel和SocketChannel实现定义读和写功能的接口而ServerSocketChannel不实现。ServerSocketChannel负责监听传入的连接和创建新的SocketChannel对象,它本身从不传输数据。
       全部socket通道类(DatagramChannel、SocketChannel和ServerSocketChannel)在被实例化时都会创建一个对等socket对象。虽然每个socket通道(在java.nio.channels包中)都有一个关联的java.net socket对象,却并非所有的socket都有一个关联的通道。如果您用传统方式(直接实例化)创建了一个Socket对象,它就不会有关SocketChannel并且它的getChannel( )方法将总是返回null。

非阻塞模式 

    要把一个socket通道置于非阻塞模式,要依靠所有socket通道类的公有超级类:SelectableChannel。

public abstract class SelectableChannel extends AbstractChannel implements Channel {     // This is a partial API listing     public abstract void configureBlocking (boolean block)            throws IOException;     public abstract boolean isBlocking( );     public abstract Object blockingLock( ); } 

    就绪选择(readiness selection)是一种可以用来查询通道的机制,该查询可以判断通道是否准备好执行一个目标操作,如读或写。

    设置或重新设置一个通道的阻塞模式:configureBlocking(),传递参数值为true则设为阻塞模式,参数值为false值设为非阻塞模式。用isBlocking( )方法来判断某个socket通道当前处于哪种模式。

     blockingLock( )方法:防止socket通道的阻塞模式被更改。只有拥有次对象的锁的线程才能更改通道的阻塞模式。该方法返回锁对象。    

Socket socket = null; Object lockObj = serverChannel.blockingLock( ); // have a handle to the lock object, but haven't locked it yet // may block here until lock is acquired synchronize (lockObj) {    // This thread now owns the lock; mode can't be changed    boolean prevState = serverChannel.isBlocking( );    serverChannel.configureBlocking (false);    socket = serverChannel.accept( );    serverChannel.configureBlocking (prevState); }

ServerSocketChannel API 

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

    ServerSocketChannel是一个基于通道的socket监听器。与java.net.ServerSocket执行相同的基本任务,但增加了通道语义。

    open( ):静态工厂方法创建新的的ServerSocketChannel对象,将返回一个未绑定的java.net.ServerSocket关联的通道。对等的ServerSocket通过在返回的ServerSocketChannel对象上调用sockete来获取。
   由于ServerSocketChannel没有bind( )方法,因此有必要取出对等的socket并使用它来绑定到一个端口以开始监听连接。

ServerSocketChannel ssc = ServerSocketChannel.open( ); ServerSocket serverSocket = ssc.socket( ); // Listen on port 1234 serverSocket.bind (new InetSocketAddress (1234)); 
    ServerSocketChannel也有accept( )方法,如果您选择在ServerSocket上调用accept( )方法,那么它会同任何其他的ServerSocket表现一样的行为:是阻塞并返回一个java.net.Socket对象。如果您选择在ServerSocketChannel上调用accept( )方法则会返回SocketChannel类型的对象,返回的对象能够在非阻塞模式下运行。

SocketChannel

public abstract class SocketChannel extends AbstractSelectableChannel  implements ByteChannel, ScatteringByteChannel, GatheringByteChannel {    // This is a partial API listing    public static SocketChannel open( ) throws IOException    public static Sock etChannel open (InetSocketAddress remote) throws IOException     public abstract Socket socket( );     public abstract boolean connect (SocketAddress remote) throws IOException;    public abstract boolean isConnectionPending( );    public abstract boolean finishConnect(  ) throws IOException;    public abstract boolean isConnected( );    public final int validOps( )  } 

    Socket 和SocketChannel 类封装点对点、有序的网络连接。SocketChannel 扮演客户端发起同一个监听服务器的连接,直到连接成功,它才能收到数据并且只会从连接到的地址接收。

    每个SocketChannel 对象创建时都是同一个对等的java.net.Socket对象串联的,静态的open( ) 方法可以创建一个新的SocketChannel 对象,而在新创建的SocketChannel 上调用socket( )方法能返回它对等的Socket 对象。

    在通道上直接调用connect( )方法或在通道关联的Socket 对象上调用connect( )来将该socket 通道连接。一旦一个socket 通道被连接,它将保持连接状态直到被关闭。在对等Socket 对象上调用connect( )方法,线程在连接建立好或超时过期之前都将保持阻塞。通过在通道上直接调用connect( )方法来建立连接并且通道处于阻塞模式(默认模式),那么连接过程实际上是一样的。

    SocketChannel 上并没有一种connect( )方法可以让您指定超时(timeout)值,当connect( )方法在非阻塞模式下被调用时SocketChannel 提供并发连接:它发起对请求地址的连接并且立即返回值。如果返回值是true,说明连接立即建立了(这可能是本地环回连接);如果连接不能立即建立,connect( )方法会返回false 且并发地继续连接建立过程。

    假如某个SocketChannel 上当前正由一个并发连接,isConnectPending( )方法就会返回true值,当通道处于中间的连接等待(connectio n-pending)状态时,您只可以调用finishConnect( ) 、isConnectPending( )或isConnected( ) 方法。

InetSocketAddress addr = new InetSocketAddress (host, port); SocketChannel sc = SocketChannel.open( ); sc.configureBlocking (false); sc.connect (addr); while ( ! sc.finishConnect( )) {     doSomethingElse( ); } doSomethingWithChannel (sc);  sc.close( );

    socketChannel是线程安全的,不需要特别的措施来保护发起的多个访问。
    socket通道是线程安全的。并发访问时无需特别措施来保护发起访问的多个线程S ocket通道是线程安全的。并发访问时无需特别措施来保护发起访问的多个线程S ocket通道是线程安全的。并发访问时无需特别措施来保护发起访问的多个线程S ocket通道是线程安全的。并发访问时无需特别措施来保护发起访问的多个线程S ocket通道是线程安全的。并发访问时无需特别措施来保护发起访问的多个线程。

    sockets是面向流的而非包导向的。它们可以保证发送的字节会按照顺序到达但无法承诺维持字节分组。某个发送器可能给一个socket写入了20个字节而接收器调用read( )方法时却只收到了其中的3个字节。剩下的17 个字节还是传输中。

    connect( )和finishConnect( )方法是互相同步的,并且只要其中一个操作正在进行,任何读或写的方法调用都会阻塞。

DatagramChannel

    DatagramChannel是模拟包导向的无连接协议(UDP/IP)。

public abstract class DatagramChannel extends AbstractSelectableChannel  implements ByteChannel, ScatteringByteChannel, GatheringByteChannel {     // This is a partial API listing     public static DatagramChannel open( ) throws IOException     public abstract DatagramSocket socket( );     public abstract DatagramChannel connect (SocketAddress remote)            throws IOException;     public abstract boolean isConnected( );     public abstract DatagramChannel disconnect( ) throws IOException;     public abstract SocketAddress receive (ByteBuffer dst) throws IOException;     public abstract int send (ByteBuffer src, SocketAddress target)      public abstract int read (ByteBuffer dst) throws IOException;     public abstract long read (ByteBuffer [] dsts) throws IOException;     public abstract long read (ByteBuffer [] dsts, int offset,  int length)           throws IOException;     public abstract int write (ByteBuffer src) throws IOException;     public abstract long write(ByteBuffer[] srcs) throws IOException;      public abstract long write(ByteBuffer[] srcs, int offset, int length)            throws IOException; }
    open()方法创建一个新实例。

    socket( ) 方法获取的对等DatagramSocket对象。DatagramChannel对象既可以充当服务器(监听者)也可以充当客户端(发送者)。如果您希望新创建的通道负责监听,那么通道必须首先被绑定到一个端口或地址/端口组合上。绑定DatagramChannel同绑定一个常规的DatagramSocket没什么区别,都是委托对等socket对象上api实现。     

DatagramChannel channel = DatagramChannel.open( ); DatagramSocket socket = channel.socket( ); socket.bind (new InetSocketAddress (portNumber));
    每个数据报(datagram)都是一个自包含的实体,拥有它自己的目的地址以及不依赖其他数据报的数据静荷。
    DatagramChannel可以发送单独的数据报给不同的目的地址,同样DatagramChannel也可以接受来自任意地址的数据包,每个到达的数据包都包含它来自何处的信息。

    

原创粉丝点击