• tcp(netty)的调用同步化(异步阻塞)及与http协议、浏览器关系【重点】


    1 https://segmentfault.com/a/1190000019152276?utm_medium=referral&utm_source=tuicool

    其实在编程领域,异步的场景还是挺多的,比如 TCP 协议本身就是异步的,我们工作中经常用到的 RPC 调用,在 TCP 协议层面,发送完 RPC 请求后,线程是不会等待 RPC 的响应结果的 。可能你会觉得奇怪,平时工作中的 RPC 调用大多数都是同步的啊?这是怎么回事呢?

    其实很简单,一定是有人帮你做了异步转同步的事情。例如目前知名的 RPC 框架 Dubbo 就给我们做了异步转同步的事情

    具体落实,就是线程间通信:

    【重要】4线程汇总-线程间通信方式

     下面我们用netty实践一下阻塞式访问,参照:/Users/joyce/work/jds/trade/trade-shenjinrong/jinceClientServer com.jincetrade.client.test.MyTestClientServer

    netty client代码:

    	public String sendToPfyh(RequestRoot msg) {
    		try {
    			Map<String, Object> map = new ConcurrentHashMap<>();
    			send(msg, map);
    			return (String)map.get("res");
    		}catch (TimeoutException te) {
    			logger.error("处理超时 {}", msg);
    		}catch (Exception e) {
    			logger.error("处理失败 {}", msg);
    			logger.error(ExceptionUtils.getStackTrace(e));
    		}
    		return null;
    	}
    
    	private void send(RequestRoot msg, Map<String, Object> map) throws Exception, URISyntaxException {
    		try {
    
    			final Bootstrap b = BootStrapManager.newBootStrap();
    			b.handler(new PfyhClientInitializer(new PfyhClientHandler(map, msg)));
    			ChannelFuture f = b.connect(GlobalConstants.PFYH_TRADE_SERVER, GlobalConstants.PFYH_TRADE_PORT);
    
    	++++++++++	f.channel().closeFuture().sync();   ++++++++++++++++++++++++++++++++++++++【重点】
    		} catch (Exception e) {
    			logger.error(ExceptionUtils.getStackTrace(e));
    		} finally {
    			ReferenceCountUtil.release(msg);
    		}
    	}
    

     此处的map也可以用一个对象来接收返回值

    f.channel().closeFuture().sync(); 这一句会阻塞当前函数,直到channel close 也可用countDownLatch.await()

    
    
    @Sharable
    public class PfyhClientHandler extends SimpleChannelInboundHandler<HttpObject>{
    
    	private Map<String, Object> map;
    	private RequestRoot msg;
    
    	private static Logger logger = LoggerFactory.getLogger(PfyhClientHandler.class); 
    
    	public PfyhClientHandler(Map _map, RequestRoot _msg) {
    		this.map = _map;
    		this.msg = _msg;
    	}
    	
    	@Override
    	public void channelActive(ChannelHandlerContext ctx) throws Exception {
    		
    		// 构造请求
    		HttpRequest request = HttpCreateor.createReq(
    				msg, GlobalConstants.PFYH_TRADE_SERVER, new URI(GlobalConstants.PFYH_TRADE_URI));
    		// 发送
    		ctx.channel().writeAndFlush(request).addListener(new ChannelFutureListener() {
    
    			@Override
    			public void operationComplete(ChannelFuture future) throws Exception {
    				logger.debug("3、消息发送成功");
    			}
    		});
    
    	}
    
    	@Override
    	protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
                    if (msg instanceof HttpContent) {  
                            HttpContent httpContent = (HttpContent) msg;  
                            // 字符数组
                            ByteBuf buf = httpContent.content();
                            // 返回
                            String response = buf.toString(Charsets.UTF_8);
    
    			map.put("res", response);      【重点】
    			logger.debug("4、收到响应: {}", response);
    			ctx.channel().close();         【重点】
    
    		}
    	}            
    

    这个地方用一个map接收返回值,更好的方案是使用自定义类包装:

    	public static class SimpleMessageHandler implements MessageHandler{
    		private BaseMsg msg;
    		public BaseMsg getMsg() {
    			return this.msg;
    		}
    		@Override
    		public void handle(BaseMsg msg) {
    			this.msg = msg;
    		}
    	}
    

    当然dubbo也可以异步调用:

    另一个tcp异步转同步的经典案例是http 1.1 协议

    取自:面试官问我:一个 TCP 连接可以发多少个 HTTP 请求?我竟然回答不上来...(https://mp.weixin.qq.com/s/lfgAjRYQr2zpfg-kpi28ZA)

    一个 TCP 连接中 HTTP 请求发送可以一起发送么(比如一起发三个请求,再三个响应一起接收)?

    HTTP/1.1 存在一个问题,单个 TCP 连接在同一时刻只能处理一个请求,意思是说:两个请求的生命周期不能重叠,任意两个 HTTP 请求从开始到结束的时间在同一个 TCP 连接里不能重叠。当然对于netty这样的异步框架,是可以以netty作为http客户端异步回调响应的,本文是http之netty客户端同步

    再比如:HTTP2 提供了 Multiplexing 多路传输特性,可以在一个 TCP 连接中同时完成多个 HTTP 请求。

    浏览器对同一 Host 建立 TCP 连接到数量有没有限制?

    假设我们还处在 HTTP/1.1 时代,那个时候没有多路传输,当浏览器拿到一个有几十张图片的网页该怎么办呢?肯定不能只开一个 TCP 连接顺序下载,那样用户肯定等的很难受,但是如果每个图片都开一个 TCP 连接发 HTTP 请求,那电脑或者服务器都可能受不了,要是有 1000 张图片的话总不能开 1000 个TCP 连接吧,你的电脑同意 NAT 也不一定会同意。

    所以答案是:有。Chrome 最多允许对同一个 Host 建立六个 TCP 连接。不同的浏览器有一些区别。

    因为http是同步协议,所以像第1点这里用netty客户端也不能异步,因为发的第二个请求对方不鸟

    3

    2019.12.5 补充

    其实tcp nagle本身(部分req)也是异步转同步的:socket缓冲区与沾包 nagle in tcp

    发送第一个包-阻塞等待ack-发送第二个包

    4

    2019.12.27

    24netty(二十)http代理服务器 实践了2中浏览器方面的规则

    Netty 作为 http client 请求https 的 get与post 再次实践了netty client同步阻塞http请求

    5

    2020.11.25

    对于没有requestid的请求,必须使用同步模式,这在2019年上半年使用netty作为httpclient的实践中已经实践,也就是本文第1点,在jds-td项目中也有应用

  • 相关阅读:
    [AWS Architect] CloudFront
    [AWS SAP] Architecture Patterns Monitoring, Logging and Auditing
    [Next.js] Create an API Route Using the nextconnect Package
    [AWS SAP] Architecture Patterns – Compute
    [Javascript] Conditional add prop to Object
    [Javascript] Using Map to set dynamic key and value
    [Next.js] Hide Sensitive Information from the Consumers of Next.js API
    [AWS] Control ALB to only allow access from CloudFront
    [AWS Architecture Patterns] Security
    [Typescript] Dealing with union types
  • 原文地址:https://www.cnblogs.com/silyvin/p/11506201.html
Copyright © 2020-2023  润新知