綜述
http2Client實現自ClientTransport介面
http2Server實現自ServerTransport介面
https://github.com/messixukej...
在liangzhiyang/annotate-grpc-go基礎上補充了部分注釋
用戶端:http用戶端串連建立
原理(引自http2-spec/HTTP2中英對照版(06-29).md at master · fex-team/http2-spec · GitHub.md)):
Upon establishment of a TCP connection and determination that HTTP/2 will be used by both peers, each endpoint MUST send a connection preface as a final confirmation and to establish the initial SETTINGS parameters for the HTTP/2 connection.
在建立TCP串連並且檢測到HTTP/2會被各個對等端使用後,每個端點必鬚髮送一個串連序言最終確認並作為建立HTTP/2串連的初始設定參數。
The client connection preface starts with a sequence of 24 octets, which in hex notation are:
用戶端串連序言以24個位元組的序列開始,以十六進位表示是:
0x505249202a20485454502f322e300d0a0d0a534d0d0a0d0a
(the string PRI * HTTP/2.0rnrnSMrnrn). This sequence is followed by a SETTINGS frame (Section 6.5). The SETTINGS frame MAY be empty.
(字串PRI * HTTP/2.0rnrnSMrnrn)。這個序列後跟著一個設定幀,其可為空白幀。
The server connection preface consists of a potentially empty SETTINGS frame (Section 6.5) that MUST be the first frame the server sends in the HTTP/2 connection.
服務端串連序言包含一個有可能是空的設定(SETTING)幀(章節6.5),它必須在HTTP/2串連中首個發送。
To avoid unnecessary latency, clients are permitted to send additional frames to the server immediately after sending the client connection preface, without waiting to receive the server connection preface. It is important to note, however, that the server connection preface SETTINGS frame might include parameters that necessarily alter how a client is expected to communicate with the server. Upon receiving the SETTINGS frame, the client is expected to honor any parameters established.
為了避免不必要的延遲,允許用戶端在發送用戶端串連序言之後立即發送其他額外的幀,不需要等待收到服務端串連序言。不過需要注意的是,服務端串連序言設定(SETTINGS)幀可能包含一些關於期望用戶端如何與服務端通訊的所必須修改的參數。在收到這些設定(SETTINGS)幀之後,用戶端應當遵守所有設定的參數。
Clients and servers MUST terminate the TCP connection if either peer does not begin with a valid connection preface. A GOAWAY frame (Section 6.8) can be omitted if it is clear that the peer is not using HTTP/2.
如果任何一個端點沒有以一個有效串連序言開頭,用戶端和服務端必須終止TCP串連。如果端點並沒有使用HTTP/2此時可以省略逾時(GOAWAY)幀(章節6.8)。
newHTTP2Client { conn=dial() t=基於conn建立http2Client framer 基於conn建立newFramer(conn), go t.reader() //迴圈讀取所有幀,並分發到對應流中 t.conn.Write(clientPreface) //發送preface幀給服務端 t.framer.writeSettings //發送setting幀。疑問:與writeWindowUpdate的關係。 t.framer.writeWindowUpdate go t.controller()//用於發送控制訊息給服務端}用戶端writeWindowUpdate兩個時機,最終作用到server端對應的handleWindowUpdate:1、newHTTP2Client->framer.writeWindowUpdate2、io.ReadFull(s1, p)->http2Client.updateWindow->t.framer.writeWindowUpdate
用戶端:建立用戶端資料流
函數:NewStream
流程:
1、建立stream:newStream
2、fc inFlow用於接收流控
3、dec=recvBufferReader用於接收資料緩衝
4、將新建立的stream加入到activeStreams
用戶端:寫資料
函數:Write
流程:
1、從s.sendQuotaPool.acquire()、t.sendQuotaPool.acquire()擷取發送資料許可權
2、從t.writableChan擷取寫入權限。(writableChan用於控制write序列化。寫入表示釋放鎖,讀取表示擷取鎖。)
3、t.framer.writeData向服務端發送資料
用戶端:讀資料
函數:reader
流程:
1、擷取setting幀
2、迴圈擷取所有幀,並分發給到相應的stream上。
服務端
與用戶端代碼基本類似不再細講。主要差異是HandleStreams,該方法用於接收用戶端請求。
資料流處理:
1、handleData接收資料->資料通過Stream.write寫入Stream.buf
2、operateHeaders handle參數為對應的資料接收處理策略。讀取Stream.buf 中寫入的資料進行相應處理。
其中server.go中實現是:
2.1、processUnaryRPC 處理流程: 接收訊息p.recvMsg -> 處理md.Handler -> 發送響應s.sendResponse -> 回複狀態t.WriteStatus
2.2、processStreamingRPC處理流程:建立serverStream -> sd.Handler -> t.WriteStatus
3、步驟2中的Handler是RegisterService注入的。