转自:http://xm-king.iteye.com/blog/766330
之前研究了JAVA NIO 与 IO,详情请点击打开链接,顺理也写写下实例。
server端:
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
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 NIOServer {
/**标识数字*/
private int flag = 0;
/**缓冲区大小*/
private int block_size = 4096;
/**接收数据的缓冲区*/
private ByteBuffer sendBuffer = ByteBuffer.allocate(block_size);
/**发送数据的缓冲区*/
private ByteBuffer receiveBuffer = ByteBuffer.allocate(block_size);
/**选择器*/
private Selector selector;
public NIOServer(int port) throws IOException{
//打开服务器套接字通道
ServerSocketChannel channel = ServerSocketChannel.open();
//服务器配置为非阻塞
channel.configureBlocking(false);
//检索与此通道关联的服务器套接字
ServerSocket server = channel.socket();
//绑定端口到通道
server.bind(new InetSocketAddress(port));
//通过open()找到选择器
selector = Selector.open();
//注册到选择器,等待连接
channel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("server start on port " + port + ".");
}
private void listen() throws IOException{
while(true){
//选择一组键,并且相应的通道已经打开
selector.select();
//返回此选择器的已选择键集合
Set<SelectionKey> keys = selector.selectedKeys();
Iterator<SelectionKey> iter = keys.iterator();
while(iter.hasNext()){
SelectionKey key = iter.next();
iter.remove();
handleKey(key);
}
}
}
private void handleKey(SelectionKey key) throws IOException{
//接受请求
ServerSocketChannel server = null;
SocketChannel client = null;
String receiveText;
String sendText;
int count = 0;
//检查些键的通道是否已准备好接受新的套接字链接
if(key.isAcceptable()){
//返回为之创建此键的通道
server = (ServerSocketChannel) key.channel();
//接受此通道套接字的连接, 此方法返回的套接字通道(如果有)将处于阻塞模式。
client = server.accept();
//设置为非阻塞
client.configureBlocking(false);
//注册到选择器,等待连接
//Operation-set bit for read operations.
client.register(selector, SelectionKey.OP_READ);
}else if(key.isReadable()){//Tests whether this key's channel is ready for reading.
// 返回为之创建此键的通道
client = (SocketChannel) key.channel();
//将缓冲区清空以备下次读取
receiveBuffer.clear();
//读取服务器发送来的数据到缓冲区中
count = client.read(receiveBuffer);
if(count > 0){
receiveText = new String(receiveBuffer.array(), 0, count);
System.out.println("server receive data from client:" + receiveText);
//Operation-set bit for write operations.
client.register(selector, SelectionKey.OP_WRITE);
}
}else if(key.isWritable()){//Tests whether this key's channel is ready for writing.
//将缓冲区清空以备下次写入
sendBuffer.clear();
//返回为之创建些键的通道
client = (SocketChannel) key.channel();
sendText = "message from server--" + flag++ + "\r\n\r\n";
//向缓冲区中写入数据
sendBuffer.put(sendText.getBytes());
//将缓冲区各标志复位,因为向里面put了数据标志被改变要想从中读取数据发向服务器,就要复位
sendBuffer.flip();
//输出到通道
client.write(sendBuffer);
System.out.println("server send to client:" + sendText);
//Operation-set bit for read operations.
client.register(selector, SelectionKey.OP_READ);
}
}
public static void main(String[] args) throws IOException{
new NIOServer(8080).listen();
}
}
client端:
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
public class NIOClient {
/*标识数字*/
private static int flag = 0;
/*缓冲区大小*/
private static int block_size = 4096;
/*接受数据缓冲区*/
private static ByteBuffer sendbuffer = ByteBuffer.allocate(block_size);
/*发送数据缓冲区*/
private static ByteBuffer receivebuffer = ByteBuffer.allocate(block_size);
/*服务器端地址*/
private final static InetSocketAddress server =
new InetSocketAddress("localhost", 8080);
public static void main(String[] args) throws IOException{
// 打开socket通道
SocketChannel channel = SocketChannel.open();
// 设置为非阻塞方式
channel.configureBlocking(false);
// 打开选择器
Selector selector = Selector.open();
// 注册连接服务端socket动作
//Operation-set bit for socket-connect operations.
channel.register(selector, SelectionKey.OP_CONNECT);
//连接
channel.connect(server);
// 分配缓冲区大小内存
Set<SelectionKey> selectionKeys;
Iterator<SelectionKey> iterator;
SelectionKey selectionKey;
SocketChannel client;
String receiveText;
String sendText;
int count=0;
while (true) {
//选择一组键,其相应的通道已为 I/O 操作准备就绪。
//此方法执行处于阻塞模式的选择操作。
selector.select();
//返回此选择器的已选择键集。
selectionKeys = selector.selectedKeys();
//System.out.println(selectionKeys.size());
iterator = selectionKeys.iterator();
while (iterator.hasNext()) {
selectionKey = iterator.next();
if (selectionKey.isConnectable()) {
System.out.println("client connect.");
client = (SocketChannel) selectionKey.channel();
// 判断此通道上是否正在进行连接操作。
// 完成套接字通道的连接过程。
if (client.isConnectionPending()) {
client.finishConnect();
System.out.println("完成连接!");
sendbuffer.clear();
sendbuffer.put("Hello,Server".getBytes());
sendbuffer.flip();
client.write(sendbuffer);
}
client.register(selector, SelectionKey.OP_READ);
} else if (selectionKey.isReadable()) {
client = (SocketChannel) selectionKey.channel();
//将缓冲区清空以备下次读取
receivebuffer.clear();
//读取服务器发送来的数据到缓冲区中
count=client.read(receivebuffer);
if(count>0){
receiveText = new String( receivebuffer.array(),0,count);
System.out.println("客户端接受服务器端数据--:"+receiveText);
client.register(selector, SelectionKey.OP_WRITE);
}
} else if (selectionKey.isWritable()) {
sendbuffer.clear();
client = (SocketChannel) selectionKey.channel();
sendText = "message from client--" + (flag++);
sendbuffer.put(sendText.getBytes());
//将缓冲区各标志复位,因为向里面put了数据标志被改变要想从中读取数据发向服务器,就要复位
sendbuffer.flip();
client.write(sendbuffer);
System.out.println("客户端向服务器端发送数据--:"+sendText);
client.register(selector, SelectionKey.OP_READ);
}
}
selectionKeys.clear();
}
}
}