
前言
使用JAVA NIO模拟请求百度,需要了解的概念
JAVA NIO 模拟请求百度
首先用阻塞方式实现,下面是完整代码
/**
* @author scott
* @create 2019-10-31
*/
public class SocketClientDemo {
SocketChannel socketChannel = null;
try {
//第1步 建立通道,此时并未连接网络
//open接口创建的Channel并没有进行连接网络,需要使用connect接口
socketChannel = SocketChannel.open();
//第2步 设置SocketChannel的阻塞模式,这里是阻塞模式
//socketChannel默认阻塞,可以不设置
socketChannel.configureBlocking(true);
//第3步 建立连接,这里请求百度的80端口
//此时才真正的连上网络
//阻塞模式,此时线程会阻塞,直到连接成功或者失败
socketChannel.connect(new InetSocketAddress("www.baidu.com",80));
//第4步 判断是否连接成功
//调用isConnected接口,当且仅当Channel是open状态且已经连接成功是才会返回true
if (socketChannel.isConnected()) {
//说明已经连接上
//准备请求数据,
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("GET / HTTP/1.1\r\n");
stringBuffer.append("Host: www.baidu.com\r\n");
stringBuffer.append("\r\n");
//\r\n\r\n表示HTTP头部结束
//将数据写进写入通道的缓冲区
ByteBuffer writeBuffer = ByteBuffer.wrap(stringBuffer.toString().getBytes());
//将写入通道缓冲区中的数据写入通道
while (writeBuffer.hasRemaining()) {
socketChannel.write(writeBuffer);
}
//清空准备写入通道的缓冲区
writeBuffer.clear();
//创建一个读取的缓冲区
ByteBuffer readBuffer = ByteBuffer.allocate(1024);
StringBuffer result = new StringBuffer();
int read = socketChannel.read(readBuffer);
while (read > 0) {
result.append(new String(readBuffer.array(),0,read,"UTF-8"));
// 清空缓冲区,继续写入
readBuffer.clear();
//当socketChannel没有数据时,线程阻塞
read = socketChannel.read(readBuffer);
}
System.out.println("##########最后的结果\n");
System.out.println(result.toString());
} else {
System.out.println("链接失败");
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//最后要关闭socketChannel
if (socketChannel != null) {
try {
socketChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
非阻塞方式实现,SocketChannel + Selector,下面是完整代码
/**
* @author scott
* @create 2019-10-31
*/
public class SocketClientDemo {
protected SocketChannel socketChannel;
protected Selector selector;
@Test
public void socketClientDemo () {
try {
//建立通道
socketChannel = SocketChannel.open();
//非阻塞通道
socketChannel.configureBlocking(false);
//建立连接
socketChannel.connect(new InetSocketAddress("www.baidu.com",
80));
//创建选择器
selector = Selector.open();
/**
* 第二个参数指定该选择器感兴趣的事件
* 事件主要有:
* {@link SelectionKey}
* SelectionKey.OP_CONNECT 连接就绪
* SelectionKey.OP_READ 读就绪
* SelectionKey.OP_WRITE 写就绪
* SelectionKey.OP_ACCEPT 接受就绪
*/
socketChannel.register(selector,
SelectionKey.OP_CONNECT);
//监听通道事件
Boolean flg = true;
while (flg) {
/**
* selector选择就绪的通道
* selector.select(); 没有就绪通道时会阻塞
* selector.selectNow(); 没有就绪通道直接立即返回0
* selector.select(long timeout); 没有就绪通道,超时后立即返回0
*/
int readyChannels = selector.selectNow();
if (readyChannels == 0) {
continue;
}
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
//遍历事件
while (keyIterator.hasNext()) {
SelectionKey key = keyIterator.next();
if (key.isConnectable()) {
System.out.println("连接就绪\r");
SocketChannel channel = (SocketChannel) key.channel();
channel.configureBlocking(false);
if (channel.finishConnect()) {
write(channel);
//数据写入完成后,设置监听read
channel.register(selector, SelectionKey.OP_READ);
}
} else if (key.isReadable()) {
System.out.println("读取就绪");
SocketChannel channel = (SocketChannel) key.channel();
channel.configureBlocking(false);
if (channel.isConnected()) {
read((SocketChannel) key.channel());
}
//表示完成一次读写操作,退出循环
flg = false;
}
keyIterator.remove();
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//最后关闭通道,关闭选择器
try {
if (socketChannel != null) {
socketChannel.close();
}
if (selector != null) {
selector.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 向通道内写入数据
* @param socketChannel
* @throws IOException
*/
private void write(SocketChannel socketChannel) throws IOException {
if (socketChannel.isConnected()) {
//写入
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("GET / HTTP/1.1\r\n");
stringBuffer.append("Host: www.baidu.com\r\n");
stringBuffer.append("\r\n");
ByteBuffer writeBuffer = ByteBuffer.wrap(stringBuffer.toString().getBytes());
System.out.println("开始写入通道");
System.out.println(stringBuffer.toString());
while (writeBuffer.hasRemaining()) {
socketChannel.write(writeBuffer);
}
}
}
/**
* 从通道内读取数据
* @param socketChannel
* @throws IOException
*/
private void read(SocketChannel socketChannel) throws IOException {
if (socketChannel.isConnected()) {
//读取
ByteBuffer readBuffer = ByteBuffer.allocate(1024);
StringBuffer result = new StringBuffer();
int read = socketChannel.read(readBuffer);
while (read > 0) {
result.append(new String(readBuffer.array(),
0,
read,
"UTF-8"));
// 清空缓冲,继续写入
readBuffer.clear();
read = socketChannel.read(readBuffer);
}
System.out.println("开始读取数据\r");
System.out.println(result.toString());
}
}
}
网友评论