RT: 有注释信息的代码在:https://github.com/yuanyangen/go_learning/tree/master/src/learning
上述代码是从golang1.5.2中得到的http部分源代码
在分析该源码过程中, 得到的简易流程图是:
在上述的流程中:不同颜色的方框表示不同的协程, 上图并没有完全将所有的细节 都展示出来,只是一个最基本的功能的描述, 而方框中的文字表示该处理的代码在哪个包下面的具体函数。
对于具体的详细处理流程, 请查看源代码。
在代码中出现的部分问题
1: 如果http响应t经过了gzip编码, 那么是什么时候进行解码的?
在代码位置: https://github.com/yuanyangen/go_learning/blob/master/src/learning/transport.go#L956,
如果在
resp.Body = &gzipReader{body: resp.Body}
代码之前使用
msg,_:= ioutil.ReadAll(resp.Body)
fmt.Println将body中的信息打印出来, 那么得到的饿信息就是经过gzip编码的,
在956行之后将代码打印出来, 得到的信息就是gzip解码之后的, 这个是为什么?
答案在于接口,这个就是golang的接口的一种用法:
在这个代码中, 传入ioutil.ReadAll方法的参数需要时实现了readcloser 接口的一个指针,就是说任何对象或者指针,只要其实现了read方法和close方法, 就能够传入到这个函数中, 最初在调用956行之前, ioutil.readAll方法最终会调用byte.readFrom方法, 代码如下:
https://github.com/golang/go/blob/master/src%2Fbytes%2Fbuffer.go#L176
注意在176hang中的read方法, 这个就是问题的关键,如果传入的参数是gzipreader的方法, 则最终会调用gzipReaderd的read方法。而在这个方法中, 定义了对gzip的解压, 而这就是在代码注释中的“lanzily call的意思”。
2:整个代码的逻辑是否略显混乱?整个代码的层级结构是怎样的?
这个代码实际上都是http包,无论是roundtrip, 还是transport, 都是网络相关的东西, 并不是tcp/ip的传输层,只是他在代码实现的过程中取了这个名字, 让我有点误解。
3:http连接池的管理方式
长链接一般是在应用层中进行处理的,首先说长连接就是充分利用了tcp的连接特性,在一次建立了一次tcp的连接后, 并没有立马将连接断开, 而是将这个保留起来作为下一个请求使用, 这个涉及到哪些方面“
1: 谁能复用连接? 只有访问特定IP的特定端口(这里一般指定了协议),那么下一次的访问就能否复用上一次建立, 同时还没有断开的连接
2:连接池是什么? 就是对1里面提到的连接的管理的数据, 可以可以是各种数据结构, 在golang的http client中, 是通过协程和chan实现的, 实现的方式如图:
图如下:
在这个连接池管理的模型中, 所有的连接信息都保存在idleConn与idleConnCh之中, 其中这两个都是关联数组, 而其中的key都是连接的信息, 所以对于每个同样的连接需求而言,不同的协程之间就通过存在于idleConnch中的channel进行通信, 而已经建立的连接就放在idleConn中
有疑问加站长微信联系(非本文作者)