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. iOS cocos2d 2游戏开发实战(第3版)书评

    2013是游戏爆发的一年,手游用户也是飞速暴增.虽然自己不做游戏,但也是时刻了解手机应用开发的新动向.看到CSDN的"写书评得技术图书赢下载分"活动,就申请了一本<iOS c ...

  2. HDU3037 附Lucas简单整理

    Saving Beans Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Tota ...

  3. IIPP迷你项目(四)"Pong"

    1 小球在墙面的反弹 1-1 让小球在画布上匀速运动 在这一步中,首先应该明确小球是如何匀速运动的.它的方法是规定一个列表v,Scott老师说这代表着“速度(Velocity)”,但是我觉得也可以拿“ ...

  4. 2015-02-09——js笔记

    示例1: 增加样式表 示例代码: function addStylesheet(url, media) {                var link = document.createEleme ...

  5. [NOIP2018TG]旅行

    [NOIP2018TG]旅行 树很简单,对每个点sort儿子,贪心走就行了 基环树呢? 如果是1e5可能不太好做 但是5000的话枚举断边就可以\(n^2\)了 #include<bits/st ...

  6. php中定时计划任务的实现原理

    根据php手册简单介绍一些相关的知识: 1.连接处理: 在 PHP 内部,系统维护着连接状态,其状态有三种可能的情况: 0 - NORMAL(正常) 1 - ABORTED(异常退出) 2 - TIM ...

  7. 4.3 使用STM32控制MC20进行GPRS通讯

    需要准备的硬件 MC20开发板 1个 https://item.taobao.com/item.htm?id=562661881042 GSM/GPRS天线 1根 https://item.taoba ...

  8. PyQt4 UI设计和调用 使用eric6

    使用工具eric6 安装包地址: http://eric-ide.python-projects.org/eric-download.html 1.需要安装python和pyqt为前提,然后安装eri ...

  9. Computer Information

    Lab: lxw@lxw-PC:python$ df -h 文件系统 容量 已用 可用 已用% 挂载点 /dev/sda7 190G .4G 175G % / none .0K .0K % /sys/ ...

  10. "深入理解C语言" 指针

    本文对coolshell中的"深入理解C语言"这篇文章中提到的指针问题, 进行简要的分析. #include <stdio.h> int main(void){ ]; ...