NIO之SocketChannel简单使用

来源:互联网 发布:狸窝转换器mac版 编辑:程序博客网 时间:2024/05/21 09:15


客户端:

import java.io.IOException;import java.net.InetSocketAddress;import java.nio.ByteBuffer;import java.nio.CharBuffer;import java.nio.channels.SocketChannel;import java.nio.charset.Charset;import java.nio.charset.CharsetDecoder;public class SocketChannelTest{public static void main(String[] args) throws IOException{SocketChannel socket = SocketChannel.open();socket.configureBlocking(false);//设置非阻塞状态 则在connect返回之前可以执行下一步while(!socket.finishConnect())判断socket.connect(new InetSocketAddress("localhost",50000));//如果不设置为非阻塞模式 则connect是阻塞方法 while(!socket.finishConnect()){System.out.println("waiting");}ByteBuffer buffer = ByteBuffer.allocate(1024);int i = -100;while((i = socket.read(buffer))!=-1){//读取信息 默认为阻塞的 可通过socket.configureBlocking(false)设置为非阻塞 非阻塞模式下 返回读取的文件字节数 如果没有 则返回0 如果该通道已到达流的末尾,则返回 -1 if( i != 0){buffer.flip();//一定要flip,read会改变position的值System.out.println(buffer.position()+"  "+buffer.limit());String info = getString(buffer);System.out.println(info);buffer.clear();}}System.out.println("done");socket.close();}/** * 将ByteBuffer转成字符串 * @param buffer * @return */public static String getString(ByteBuffer buffer)  {  Charset charset = null;  CharsetDecoder decoder = null;  CharBuffer charBuffer = null;  try  {  charset = Charset.forName("UTF-8");  decoder = charset.newDecoder();  // charBuffer = decoder.decode(buffer);//用这个的话,只能输出来一次结果,第二次显示为空  charBuffer = decoder.decode(buffer.asReadOnlyBuffer());  return charBuffer.toString();  }  catch (Exception ex)  {  ex.printStackTrace();  return "";  }  }  }


这里需要注意的是:


在非阻塞模式下调用connect( )方法之后,SocketChannel又被切换回了阻塞模式。那么如果有必要的话,调用线程会阻塞直到连接建立完成,finishConnect( )方法接着就会返回true值。

设置非阻塞模式时一定要调用finishConnect()来完成连接  否则读写操作将会报错NotYetConnectedException

下面是finishConnect的API解释:

finishConnect

public abstract boolean finishConnect()                               throws IOException
完成套接字通道的连接过程。

通过将套接字通道置于非阻塞模式,然后调用其 connect 方法来发起非阻塞连接操作。一旦建立了连接,或者尝试已失败,该套接字通道就变为可连接的,并且可调用此方法完成连接序列。如果连接操作失败,则调用此方法将导致抛出合适的IOException

如果已连接了此通道,则不阻塞此方法并且立即返回 true。如果此通道处于非阻塞模式,那么当连接过程尚未完成时,此方法将返回 false。如果此通道处于阻塞模式,则在连接完成或失败之前将阻塞此方法,并且总是返回true 或抛出描述该失败的、经过检查的异常。

可在任意时间调用此方法。如果正在调用此方法时在此通道上调用读取或写入操作,则在此调用完成前将首先阻塞该操作。如果试图发起连接但失败了,也就是说如果调用此方法导致抛出经过检查的异常,则关闭此通道。

返回:
当且仅当已连接此通道的套接字时才返回 true
抛出:
NoConnectionPendingException - 如果未连接此通道并且尚未发起连接操作
ClosedChannelException - 如果此通道已关闭
AsynchronousCloseException - 如果正在进行连接操作时另一个线程关闭了此通道
ClosedByInterruptException - 如果正在进行连接操作时另一个线程中断了当前线程,因此关闭了该通道并将当前线程设置为中断状态
IOException - 如果发生其他 I/O 错误




关于SocketChannel的read方法返回值:

(read后position的值会变化)

转自http://blog.csdn.net/pingnanlee/article/details/9712439

1、read什么时候返回-1

read返回-1说明客户端的数据发送完毕,并且主动的close socket。所以在这种场景下,你需要关闭socketChannel并且取消key,最好是退出当前函数。注意,这个时候服务端要是继续使用该socketChannel进行读操作的话,就会抛出“远程主机强迫关闭一个现有的连接”的IO异常。

2、read什么时候返回0

其实read返回0有3种情况,一是某一时刻socketChannel中当前(注意是当前)没有数据可以读,这时会返回0,其次是bytebuffer的position等于limit了,即bytebuffer的remaining等于0,这个时候也会返回0,最后一种情况就是客户端的数据发送完毕了,这个时候客户端想获取服务端的反馈调用了recv函数,若服务端继续read,这个时候就会返回0。





服务端:

import java.io.IOException;import java.net.InetSocketAddress;import java.net.ServerSocket;import java.net.Socket;import java.nio.ByteBuffer;import java.nio.channels.ServerSocketChannel;import java.nio.channels.SocketChannel;public class ServerSocketChannelTest{public static void main(String[] args) throws IOException{int port = 50000;ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();  //serverSocketChannel.configureBlocking(false);  ServerSocket serverSocket = serverSocketChannel.socket();  serverSocket.bind(new InetSocketAddress(port));  //绑定端口serverSocketChannel.configureBlocking(false);  //设置成非阻塞模式 即不会再accept因为等待连接而阻塞  如果没有连接则立即返回null //System.out.println(serverSocketChannel.isBlocking());while(true){SocketChannel socket = serverSocketChannel.accept();if(socket!=null){System.out.println("accept connect from "+socket.getLocalAddress());ByteBuffer buffer = ByteBuffer.allocate(1024);buffer.put("hello".getBytes());//法送hello信息buffer.flip();//position回置socket.write(buffer);}}}}


0 0
原创粉丝点击