netty学习记录(2)
nio学习:
package com.zhuguozhu.client;
/**
* nio的客户端
* @author Guozhu Zhu
* @date 2018/4/13
* @version 1.0
*/
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
public class Client {
public static void main(String[] args) {
InetSocketAddress address = new InetSocketAddress("127.0.0.1", 8379);
SocketChannel sc = null;
ByteBuffer buffer = ByteBuffer.allocate(1024);
try {
//打开通道
sc = SocketChannel.open();
//建立连接
sc.connect(address);
while (true) {
byte[] bytes = new byte[1024];
System.in.read(bytes);
//把输入的数据放入buffer缓冲区
buffer.put(bytes);
//复位操作
buffer.flip();
//将buffer的数据写入通道
sc.write(buffer);
//清空缓冲区中的数据
buffer.clear();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (sc != null) {
try {
sc.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
package com.zhuguozhu.p1;
/**
* IntBufferTest(Buffer常用类)
* @author Guozhu Zhu
* @date 2018/1/14
* @verison 1.0
*/
import java.nio.IntBuffer;
public class IntBufferTest {
public static void main(String[] args) {
//1、基本操作
//创建指定长度的缓冲区
/*IntBuffer buffer = IntBuffer.allocate(10);
buffer.put(11); //position位置:0->1
buffer.put(5); //position位置:1->2
buffer.put(32); //position位置:2->3
System.out.println("未调用flip复位方法前的buffer:" + buffer);
//把位置复位为0,也就是position位置由3->0
buffer.flip();
//比较未调用flip方法和调用之后buffer的limit可以发现,不进行复位操作的话,position的值为3,limit的值为10
// 因为缓冲区中已有11、5、32三个元素,也就意味着put()方法会使position向后递增1
System.out.println("调用flip复位方法后的buffer:" + buffer);
System.out.println("buffer容量为:" + buffer.capacity());
System.out.println("buffer限制为:" + buffer.limit());
System.out.println("获取下标为1的元素:" + buffer.get(1));
System.out.println("调用get(index)方法后的buffer:" + buffer); //调用get(index)方法,不会改变position的值
buffer.put(1, 4); //将buffer位置为1的值替换为4,调用put(index,value)不会改变position的值
System.out.println("调用put(index, value)方法后的buffer:" + buffer);
for(int i=0; i<buffer.limit(); i++) {
//调用get方法会使缓冲区的位置(position)向后递增一位
System.out.print(buffer.get() + "\t");
}
System.out.println("\nbuffer对象遍历之后buffer为:" + buffer);*/
//2、wrap方法的使用
/*int[] arr = new int[]{1, 2, 3};
IntBuffer buffer = IntBuffer.wrap(arr);
System.out.println("wrap(arr)方法:" + buffer);
//IntBuffer.wrap(array, postion, length)表示容量为array的长度,但是可操作的元素为位置postion到length的数组元素
buffer = IntBuffer.wrap(arr, 0, 2);
System.out.println("wrap(arr, 0, 2):" + buffer);*/
//3、其他方法
IntBuffer buffer = IntBuffer.allocate(10);
int[] arr = new int[]{1, 2, 3};
buffer.put(arr);
System.out.println("调用put(arr)方法后的buffer:" + buffer);
//一种复制方法,buffer1的pos、lim、cap与buffer的一样
IntBuffer buffer1 = buffer.duplicate();
System.out.println("buffer1:" + buffer1);
buffer.position(1); //将buffer的position设置为1,不建议使用。功能相当于flip()方法,但是从运行结果可以看出,lim依然等于10
System.out.println("调用position()方法后的buffer:" + buffer);
System.out.println("buffer的可读数据量:" + buffer.remaining()); //计算出从pos到lim的长度
int[] arr1 = new int[buffer.remaining()];
//将缓冲区的数据放入arr1中
buffer.get(arr1);
for(Integer i : arr1) {
System.out.print(Integer.toString(i) + ",");
}
System.out.println();
//比较flip()方法和position(index)方法的区别
buffer1.flip();
System.out.println("buffer1的可读数量:" + buffer1.remaining());
arr1 = new int[buffer1.remaining()];
buffer1.get(arr1);
for(Integer i : arr1) {
System.out.print(Integer.toString(i) + ",");
}
}
}
package com.zhuguozhu.server;
/**
* nio的服务器端
* @author Guozhu Zhu
* @date 2018/4/13
* @version 1.0
*/
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.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
public class Server implements Runnable {
private Selector selector;
private ByteBuffer buffer = ByteBuffer.allocate(1024);
public Server(int port) {
try {
//1 打开多路复用器
selector = Selector.open();
//2 打开服务器通道
ServerSocketChannel ssc = ServerSocketChannel.open();
//3 设置服务器通道为非阻塞方式
ssc.configureBlocking(false);
//4 绑定地址
ssc.bind(new InetSocketAddress(port));
//5 把服务器通道注册到多路复用选择器上,并监听阻塞状态
ssc.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("Server start, port:" + port);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
while (true) {
try {
//1 必须让多路复用选择器开始监听
selector.select();
//2 返回所有已经注册到多路复用选择器上的通道的SelectionKey
Iterator<SelectionKey> keys = selector.selectedKeys().iterator();
//3 遍历keys
while (keys.hasNext()) {
SelectionKey key = keys.next();
keys.remove();
if (key.isValid()) { //如果key的状态是有效的
if(key.isAcceptable()) { //如果key是阻塞状态,则调用accept()方法
accept(key);
}
if(key.isReadable()) { //如果key是可读状态,则调用read()方法
read(key);
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void accept(SelectionKey key) {
try {
//1 获取服务器通道
ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
//2 执行阻塞方法
SocketChannel sc = ssc.accept();
//3 设置阻塞模式为非阻塞
sc.configureBlocking(false);
//4 注册到多路复用选择器上,并设置读取标识
sc.register(selector, SelectionKey.OP_READ);
} catch (Exception e) {
e.printStackTrace();
}
}
private void read(SelectionKey key) {
try {
//1 清空缓冲区中的旧数据
buffer.clear();
//2 获取之前注册的SocketChannel通道
SocketChannel sc = (SocketChannel) key.channel();
//3 将sc中的数据放入buffer中
int count = sc.read(buffer);
if(count == -1) { // == -1表示通道中没有数据
key.channel().close();
key.cancel();
return;
}
//读取到了数据,将buffer的position复位到0
buffer.flip();
byte[] bytes = new byte[buffer.remaining()];
//将buffer中的数据写入byte[]中
buffer.get(bytes);
String body = new String(bytes).trim();
System.out.println("Server:" + body);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new Thread(new Server(8379)).start();
}
}