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 連接。不同的瀏覽器有一些區別。

 

 

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請求


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM