2
2
3
3
首先,我最关心的是,他是怎么处理数据流的。GRPC框架采用了HTTP2作为通讯协议,而HTTP2是基于TCP协议(传输控制协议)。TCP协议传输数据是通过数据流的方式传输,所以grpc也绕不开数据流的处理。
4
4
5
- 先看看发送数据函数:
5
+ 先看看发送数据函数:
6
+
7
+ stream.go
6
8
7
9
``` go
8
10
func (cs *clientStream ) SendMsg (m interface {}) (err error ) {
@@ -62,6 +64,8 @@ func (cs *clientStream) SendMsg(m interface{}) (err error) {
62
64
63
65
prepareMsg函数如下:
64
66
67
+ stream.go
68
+
65
69
``` go
66
70
func prepareMsg (m interface {}, codec baseCodec , cp Compressor , comp encoding .Compressor ) (hdr , payload , data []byte , err error ) {
67
71
if preparedMsg , ok := m.(*PreparedMsg); ok {
@@ -84,6 +88,8 @@ func prepareMsg(m interface{}, codec baseCodec, cp Compressor, comp encoding.Com
84
88
85
89
msgHeader函数如下:
86
90
91
+ rpc_util.go
92
+
87
93
``` go
88
94
func msgHeader (data , compData []byte ) (hdr []byte , payload []byte ) {
89
95
hdr = make ([]byte , headerLen)
@@ -106,6 +112,8 @@ func msgHeader(data, compData []byte) (hdr []byte, payload []byte) {
106
112
107
113
接收消息头部代码
108
114
115
+ rpc_util.go
116
+
109
117
``` go
110
118
func (p *parser ) recvMsg (maxReceiveMessageSize int ) (pf payloadFormat , msg []byte , err error ) {
111
119
if _ , err := p.r .Read (p.header [:]); err != nil {
@@ -137,7 +145,7 @@ func (p *parser) recvMsg(maxReceiveMessageSize int) (pf payloadFormat, msg []byt
137
145
}
138
146
```
139
147
140
- 注意,接收单个数据包最大长度为maxReceiveMessageSize ,默认是 4194304(4M)。
148
+ 注意,接收单个数据包最大长度为maxReceiveMessageSize (clientconn.go) ,默认是 4194304(4M)。
141
149
142
150
首先读取消息头部(5字节)。然后解析出压缩标志和消息包长度(不含消息头部大小)。最后根据消息长度读取消息内容。
143
151
@@ -149,6 +157,8 @@ func (p *parser) recvMsg(maxReceiveMessageSize int) (pf payloadFormat, msg []byt
149
157
150
158
ReadAtLeast这个函数会读取指定长度数据后再返回:
151
159
160
+ io/io.go
161
+
152
162
``` go
153
163
func ReadAtLeast (r Reader , buf []byte , min int ) (n int , err error ) {
154
164
if len (buf) < min {
@@ -170,7 +180,9 @@ func ReadAtLeast(r Reader, buf []byte, min int) (n int, err error) {
170
180
171
181
这个函数的核心就是那个for循环啦,只要读取的数据没有达到最低要求,就不断尝试读取数据,直到读够数据为止。其实粘包就在这里悄悄的实现了。
172
182
173
- readClient从接收数据channel里面取出数据:
183
+ readClient从接收数据channel里面取出数据:
184
+
185
+ internal/transport/transport.go
174
186
175
187
``` go
176
188
func (r *recvBufferReader ) readClient (p []byte ) (n int , err error ) {
@@ -192,4 +204,11 @@ GRPC框架采用HTTP2协议,而HTTP2是用过数据帧传输数据,当数据
192
204
193
205
readClient就可以从接收数据channel里面去数据啦。在传输数据较小(小于16K)的情况下,单个数据帧就能传输完毕。但是如果单个数据帧不能完成数据传输,就会用到上面提到的粘包功能了(这里也可以叫做粘帧,毕竟是通过数据帧传输数据的)。
194
206
195
- 相信通过以上分析,能对GRPC网络通信这块有一个大概的了解。这里面并没有提到HTTP2的Hpack思想,哈夫曼编码(Huffman Coding)等实现细节。有兴趣的朋友可以自己去了解下,这些仍然值得我们学习。
207
+ 相信通过以上分析,能对GRPC网络通信这块有一个大概的了解。这里面并没有提到HTTP2的HPACK思想,哈夫曼编码(Huffman Coding)等实现细节。有兴趣的朋友可以自己去了解下,这些仍然值得我们学习。
208
+
209
+ ------
210
+
211
+ 参考地址:
212
+
213
+ 1 . https://www.okcode.net/article/60025
214
+ 2 . https://blog.fundebug.com/2019/03/07/understand-http2-and-http3
0 commit comments