golang中_有两种作用,一种用在import中,比如这样
import _ "github.com/go-sql-driver/mysql"
表示并不需要导入整个包,只是执行这个包里面所有的init函数。另一个作用就是作为变量的占位符,比如req, _ := http.NewRequest(....),这里http.NewRequest返回的是两个参数,但是如果我并不需要用到error参数时,就可以用_线代替。
但是这里就有一种特殊情况了,例如,response, err := Client.Do(req),这种场景还是比较常见的,就是发起一个http请求时,当我不关心response时,是否可以用_代替而不接收这个参数呢?
答案是不可以的。因为这里发起http请求时,已经打开了一个tcp连接,如果不显式的调用 response.Body.Close()的话,是不会自动断开tcp连接的,尽管golang的gc已经完成了内存的回收,但是仍然不会关闭tcp连接。下面测试过程:这里测试请求了baidu,然后用_代替response参数,用tcpdump进行抓包
代码如下:
package main import ( log "ad-service/alog" "net/http" "strings" "time" ) func send() { req, err := http.NewRequest("GET", "http://baidu.com", strings.NewReader("")) if err != nil { log.Error(err) return } client := http.Client{} _, err := client.Do(req) //resp, err := client.Do(req) // 不调用Close if err != nil { log.Error(err) return } //defer resp.Body.Close() // 不调用Close } func main() { send() time.Sleep(1000 * time.Second) // 保持进程一直运行,当进程停止时会被操作系统强行回收资源 }
抓包结果:
可以看到请求结束之后30秒依然没有发送FIN包来断开连接。这个时候我手动Ctrl+C终止进程后:
正常进行了四次挥手。打开了文件都要关闭大家都知道,但是这里特殊的地方在于golang中使用_下划线并不是靠谱的。