package com.pt.utils;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.*;
import io.netty.util.concurrent.DefaultEventExecutorGroup;
import io.netty.util.concurrent.EventExecutorGroup; import java.net.URI;
import java.util.Map; /**
* @author panteng
* @description
* @date 17-3-20.
*/
public class NonBlockHttpClient {
public static EventLoopGroup workerGroup = new NioEventLoopGroup(1);
public static Bootstrap b = new Bootstrap();
public static final EventExecutorGroup executor = new DefaultEventExecutorGroup(2);
static {
b.group(workerGroup);
b.channel(NioSocketChannel.class);
b.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 1000);
}
public static Object lock = new Object();
/**
* 异步GET请求
*
* @param url
* @param head
* @param handler
* @return
*/
public static Boolean get(String url, Map<String, String> head, final HttpHandler handler) {
try {
URI uri = new URI(url);
String domain = uri.getHost();
Integer port = uri.getPort() < 0 ? 80 : uri.getPort();
DefaultFullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, uri.toASCIIString());
if (head == null) {
request.headers().add("Host", domain);
request.headers().add("User-Agent", "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:44.0) Gecko/20100101 Firefox/44.0");
request.headers().add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
request.headers().add("Accept-Language", "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3");
request.headers().add("Connection", "keep-alive");
request.headers().add("Cache-Control", "max-age=0");
} else {
for (Map.Entry entry : head.entrySet()) {
request.headers().add((String) entry.getKey(), entry.getValue());
}
}
ChannelInitializer channelInitializer = new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
// 客户端接收到的是httpResponse响应,所以要使用HttpResponseDecoder进行解码
socketChannel.pipeline().addLast(new HttpResponseDecoder());
// 客户端发送的是httprequest,所以要使用HttpRequestEncoder进行编码
socketChannel.pipeline().addLast(new HttpRequestEncoder());
socketChannel.pipeline().addLast(executor, new GeneralHandler(handler));
}
};
ChannelFuture f;
synchronized (lock) {
b.handler(channelInitializer);
f = b.connect(domain, port).sync();
}
f.channel().writeAndFlush(request);
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
public static void close() {
try {
executor.shutdownGracefully();
workerGroup.shutdownGracefully();
} catch (Exception e) {
e.printStackTrace();
}
}
}

核心类1

package com.pt.utils;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.HttpContent;
import io.netty.handler.codec.http.HttpResponse; import java.util.HashMap;
import java.util.Map; /**
* @author panteng
* @description
* @date 17-3-20.
*/
public class GeneralHandler extends ChannelInboundHandlerAdapter {
com.pt.utils.HttpHandler httpHandler;
Integer respLength = Integer.MAX_VALUE; // 响应报文长度
Map<String, String> head = new HashMap<String, String>();
String respContent = ""; public GeneralHandler(com.pt.utils.HttpHandler handler) {
this.httpHandler = handler;
} @Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof HttpResponse) {
HttpResponse response = (HttpResponse) msg;
for (Map.Entry entry : response.headers().entries()) {
head.put((String) entry.getKey(), (String) entry.getValue());
}
if (response.headers().get("Content-Length") != null) {
respLength = Integer.parseInt(response.headers().get("Content-Length"));
}
} if (msg instanceof HttpContent) {
HttpContent content = (HttpContent) msg;
ByteBuf buf = content.content();
respContent += buf.toString(httpHandler.getCharset());
((HttpContent) msg).release();
if (respContent.getBytes().length >= respLength || !buf.isReadable()) {
ctx.channel().close();
httpHandler.handler(head, respContent);
}
}
}
}

核心类2

package com.pt.utils;

import java.nio.charset.Charset;
import java.util.Map; /**
* @author panteng
* @description http响应的异步回调
* @date 17-3-20.
*/
public interface HttpHandler {
public void handler(Map<String, String> headMap, String body);
public Charset getCharset();
}

用户自定义处理接口

使用用例:

package com.pt.utils.test;

import com.pt.utils.HttpHandler;

import java.nio.charset.Charset;
import java.util.Map; /**
* @author panteng
* @description
* @date 17-3-20.
*/
public class MyHandler implements HttpHandler {
boolean isFinish = false;
String id; public MyHandler(String id) {
this.id = id;
} public void handler(Map<String, String> headMap, String body) {
try {
Thread.sleep(3000);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(id + "自己处理:" + body);
this.setIsFinish(true);
} public Charset getCharset() {
return Charset.forName("UTF-8");
} public boolean isFinish() {
return isFinish;
} public void setIsFinish(boolean isFinish) {
this.isFinish = isFinish;
} public String getId() {
return id;
} public void setId(String id) {
this.id = id;
}
}

用户定义处理的实现

package com.pt.utils.test;

import com.pt.utils.NonBlockHttpClient;

/**
* @author panteng
* @description
* @date 17-3-22.
*/
public class NonBlockHttpClientTest {
public static void main(String[] arges) {
MyHandler myHandler = new MyHandler("A");
MyHandler myHandler1 = new MyHandler("B");
MyHandler myHandler2 = new MyHandler("C");
MyHandler myHandler3 = new MyHandler("D");
NonBlockHttpClient
.get(url1,
null, myHandler);
NonBlockHttpClient
.get(url2,
null, myHandler1);
NonBlockHttpClient
.get(url3,
null, myHandler2);
NonBlockHttpClient
.get(url4,
null, myHandler3);
System.out.println("做别的事情");
try {
Thread.sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}
while (!(myHandler.isFinish() && myHandler1.isFinish() && myHandler2.isFinish() && myHandler3.isFinish())) {
try {
Thread.sleep(10);
} catch (Exception e) {
e.printStackTrace();
}
}
NonBlockHttpClient.close();
System.out.println("退出主函数... ...");
}
}

基于netty的异步http请求的更多相关文章

  1. suging闲谈-netty 的异步非阻塞IO线程与业务线程分离

    前言 surging 对外沉寂了一段时间了,但是作者并没有闲着,而是针对于客户的需要添加了不少功能,也给我带来了不少外快收益, 就比如协议转化,consul 的watcher 机制,JAVA版本,sk ...

  2. 基于Netty和SpringBoot实现一个轻量级RPC框架-Client端请求响应同步化处理

    前提 前置文章: <基于Netty和SpringBoot实现一个轻量级RPC框架-协议篇> <基于Netty和SpringBoot实现一个轻量级RPC框架-Server篇> & ...

  3. 在Silverlight中的DispatcherTimer的Tick中使用基于事件的异步请求

    需求:在silverlight用户界面上使用计时器定时刷新数据. 在 Silverlight 中的 DispatcherTimer 的 Tick 事件 中使用异步请求数据时,会出现多次请求的问题,以下 ...

  4. 基于Netty打造RPC服务器设计经验谈

    自从在园子里,发表了两篇如何基于Netty构建RPC服务器的文章:谈谈如何使用Netty开发实现高性能的RPC服务器.Netty实现高性能RPC服务器优化篇之消息序列化 之后,收到了很多同行.园友们热 ...

  5. 基于Netty的私有协议栈的开发

    基于Netty的私有协议栈的开发 书是人类进步的阶梯,每读一本书都使自己得以提升,以前看书都是看了就看了,当时感觉受益匪浅,时间一长就又还回到书本了!所以说,好记性不如烂笔头,以后每次看完一本书都写一 ...

  6. 《Java 编写基于 Netty 的 RPC 框架》

    一 简单概念 RPC: ( Remote Procedure Call),远程调用过程,是通过网络调用远程计算机的进程中某个方法,从而获取到想要的数据,过程如同调用本地的方法一样. 阻塞IO :当阻塞 ...

  7. java编写基于netty的RPC框架

    一 简单概念 RPC:(Remote Procedure Call),远程调用过程,是通过网络调用远程计算机的进程中某个方法,从而获取到想要的数据,过程如同调用本地的方法一样. 阻塞IO:当阻塞I/O ...

  8. 基于Netty和SpringBoot实现一个轻量级RPC框架-Client篇

    前提 前置文章: <基于Netty和SpringBoot实现一个轻量级RPC框架-协议篇> <基于Netty和SpringBoot实现一个轻量级RPC框架-Server篇> 前 ...

  9. 这样基于Netty重构RPC框架你不可能知道

    原创申明:本文由公众号[猿灯塔]原创,转载请说明出处标注 今天是猿灯塔“365天原创计划”第5天. 今天呢!灯塔君跟大家讲: 基于Netty重构RPC框架 一.CyclicBarrier方法说明 1. ...

随机推荐

  1. Android开发:使用DialogFragment实现dialog自定义布局

    使用DialogFragment实现dialog的自定义布局最大的好处是可以更好控制dialog的生命周期. TestFragment的代码: public class TestFragment ex ...

  2. POJ1182食物链(并查集经典好题)

    题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=66964#problem/E 题目思路:主要有两种思路:1.带权并查集2.挑战程 ...

  3. 【BZOJ5047】空间传送装置 最短路

    [BZOJ5047]空间传送装置 Description 太空中一共有n座星球,它们之间可以通过空间传送装置进行转移.空间传送装置分为m种,第i种装置可以用4个参数a_i,b_i,c_i,d_i来描述 ...

  4. 【BZOJ2150】部落战争 最小流

    [BZOJ2150]部落战争 Description lanzerb的部落在A国的上部,他们不满天寒地冻的环境,于是准备向A国的下部征战来获得更大的领土. A国是一个M*N的矩阵,其中某些地方是城镇, ...

  5. sqlserver 脚本和批处理指令小结

    一.脚本基础     1.USE语句          设置当前数据库.     2.声明变量          语法:DECLARE @变量名 变量类型          在声明变量后,给变量赋值之 ...

  6. jPage.js分页

    jPage.js插件使用文档 这一款插件主要是为了bootstrap原生的分页功能效果不理想而诞生的一款插件. jPage.js代码更新地址为:https://github.com/leslieSie ...

  7. Maven 手动把本地jar安装到本地仓库

    首先,你要安装的.jar包要下载下来放在电脑上面,然后maven已经配置好了,如下图: 然后,执行一下命令就可以了 mvn install:install-file -Dfile=path-to-fi ...

  8. MySQL将语句写入到binlog二进制日志中

    由于二进制日志是公共资源,所有线程都要写二进制日志,所以一定要避免两个线程同时更新二进制日志.因此,在事件组写二进制日志时,二进制日志将获得一个互斥锁LOCK_log,然后在事件组写完后释放,由于服务 ...

  9. 前端基础 & 初识CSS

    CSS介绍 CSS(Cascading Style Sheet,层叠样式表)定义如何显示HTML元素.l 当浏览器读到一个样式表,它就会按照这个样式表来对文档进行格式化(渲染). CSS语法 每个CS ...

  10. Python获取位数

    import platform platform.architecture()