NIO客户端:
package src.socket;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
/**
* @author EddyYang
*
*/
public class NBClient {
boolean ifExit = false;
SocketChannel sc ;
public SocketChannel connect(String host,int port)throws UnknownHostException,IOException{
System.out.println("客户端开始运行...");
sc = SocketChannel.open();
sc.configureBlocking(false);
InetSocketAddress inet_socket_addr = new InetSocketAddress(host,port);
sc.connect(inet_socket_addr);
if(sc.isConnectionPending()){
sc.finishConnect();
}
return sc;
}
public void request(SocketChannel sc)throws IOException{
System.out.println("请输入字符串");
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String msg = null;
ByteBuffer bytebuff = ByteBuffer.allocate(1024);
int nbytes = 0;
msg = in.readLine();
bytebuff = ByteBuffer.wrap(msg.getBytes());
nbytes = sc.write(bytebuff); //把接受到的数据传给服务器。
if(msg.equalsIgnoreCase("exit")){
ifExit = true;
}
}
public String getResponse(SocketChannel sc)throws IOException{
ByteBuffer buff= ByteBuffer.allocate(1024);
buff.clear();
sc.read(buff);
buff.flip();
Charset charset = Charset.forName("GBK");
CharsetDecoder decoder = charset.newDecoder();
CharBuffer charbuff = decoder.decode(buff);
return charbuff.toString();
}
public static void main(String[] args){
try{
NBClient nbc = new NBClient();
SocketChannel sc = nbc.connect("127.0.0.1",8888);
while(!nbc.ifExit){
/*
* 发送数据
*/
nbc.request(sc);
/*
* 接受数据
* 因为是不阻塞,有时候没有返回数据就处理了(但是可以下次在读取)
*/
String msg = nbc.getResponse(sc);
System.out.println("从服务器返回数据:"+msg);
}
}catch(IOException e){
e.printStackTrace();
}
}
}
NIO服务器端:
package src.socket; import java.io.IOException; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.util.Iterator; import java.util.Set; public class NBServer { private ServerSocketChannel server_socket_channel ; private Selector selector ; /* * response()方法用作对客户端请求的一个响应。 * SelectionKey 代表从集合中取得的消息。 * A token representing the registration of a selectableChannel with a selector. * A selection key is created each time a channel is registered with a selector. * (每一次当一个通道被注册到一个选择器时,一个SelectionKey对象就被创建) */ public void response(SelectionKey k,String msg)throws IOException{ /* * SelectionKey.channel(): * Returns the channel for which this key was created. */ SocketChannel socket_channel = (SocketChannel)k.channel(); /* * 运用allocate(1024)方法创建一个1024大小的字节缓冲区 */ ByteBuffer buffer = ByteBuffer.allocate(1024); buffer.flip(); //调整3个指针。 /* * 用 wrap()方法: * wraps a byte array into a buffer. */ buffer = ByteBuffer.wrap(msg.getBytes()); /* * 用SocketChannel的writer()方法将缓冲的内容写出去。 */ socket_channel.write(buffer); /* * 请大家思考,这里为什么要将msg变量设置为null?? */ msg = null; } /* * String processRequest(SelectionKey k)方法用做处理客户端发来的消息 * 其中要进行字节流和字符流的转换工作。 */ public String processRequest(SelectionKey k)throws IOException{ ByteBuffer buffer = ByteBuffer.allocateDirect(1024); /* * 用 selectionKey的channel()方法得到一个 SocketChannel对象 */ SocketChannel socket_channel = (SocketChannel)k.channel(); socket_channel.read(buffer); /* * 用通道读的方式将内容读到缓存当中,并且调整指针 */ buffer.flip(); Charset charset = Charset.forName("GBK"); /* * 用字符集对象 charset 的newDecoder()方法获得一个解码器对象。 */ CharsetDecoder decoder = charset.newDecoder(); /* * 在ByteBuffer中存放的是字节,但程序需要把字节转换成字符串,才能进行对字符串的操作。 */ CharBuffer charBuffer = decoder.decode(buffer); /* * retruns a string containing the characters in this buffer. */ return charBuffer.toString(); } public void init(int port)throws IOException{ System.out.println("服务器开始运行..."); /* * opens a server-socket channel. * 创建一个 ServerSocketChannel对象。 */ server_socket_channel = ServerSocketChannel.open(); /* * configureBlocking(boolean block) * Adjusts this channel's blocking mode. * 设置该通道为非阻塞的。 */ server_socket_channel.configureBlocking(false); /* * Retrieves a server socket associated with this channel. */ ServerSocket server_socket = server_socket_channel.socket(); /* * creates a socket address where the IP address is the * wildcard(通配符)address and the port number a specified value. * 用来表示Socket IP地址和端口号相结合的网络地址 */ InetSocketAddress socket_address = new InetSocketAddress(port); /* * Binds the server socket to a specific address * (IP address and the port number) */ server_socket.bind(socket_address); /* * opens a selector.打开一个选择器。 */ selector = Selector.open(); /* * Registers this channel with the given selectors,returning a selectionKey. * 表示服务器已经收到并且接收一个客户端请求。 */ server_socket_channel.register(selector,SelectionKey.OP_ACCEPT); SocketChannel socket_channel = null; while(true){ /* * 选择一组键,其相应的通道已为 I/O 操作准备就绪。 * 此方法执行处于阻塞模式的选择操作。 * 仅在至少选择一个通道、调用此选择器的 wakeup 方法,或者当前的线程已中断(以先到者为准)后此方法才返回。 * 返回:已更新其准备就绪操作集的键的数目,该数目可能为零 * * select(int i)方法,用来判断是否有事件发生;它是个阻塞方法,只要有事件发生,就返回现有事件的数量。 */ int keynum = selector.select(1000); if(keynum>0){ /* * returns this seletor's selected-key set. * selectedKeys()方法,用来从集合中取得消息,返回的也是个集合类型的。(Set) */ Set keyset = selector.selectedKeys(); Iterator it = keyset.iterator(); while(it.hasNext()){ SelectionKey select_key = (SelectionKey)it.next(); it.remove(); if(!select_key.isValid()){ select_key.cancel(); continue; } /* * test wether this key's channel is ready to accept a new socket connection. */ if(select_key.isAcceptable()){ /* * Returns the channel for which this key was created. */ ServerSocketChannel ssc = (ServerSocketChannel)select_key.channel(); /* * accepts a connection made to this channel's socket. */ socket_channel = (SocketChannel)ssc.accept(); socket_channel.configureBlocking(false); socket_channel.register(selector,SelectionKey.OP_READ); }else if(select_key.isReadable()){ try{ String msg = ""; msg = processRequest(select_key); System.out.println("从客户端收到数据:"+msg); if(msg.equalsIgnoreCase("exit")){ select_key.cancel(); continue; } if(msg.length()>0){ response(select_key,"服务器返回数据:"+msg); } }catch(Exception e){ System.out.println("出异常啦"); e.printStackTrace(); select_key.cancel(); } } } } } } public static void main(String[] args){ try{ NBServer nbserver = new NBServer(); nbserver.init(8888); }catch(IOException e){ e.printStackTrace(); } } }