######################################## 网络编程 ######################################## HTTP 请求 **************************************** 制作一个 http 请求需要用到 http 包,一个简单的示例如下: .. code-block:: go request, err := http.NewRequestWithContext(context.Background(), "GET", repo, nil) if err != nil { panic(err.Error()) } request.Header.Add("User-Agent", `'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36 Edg/87.0.664.66'`) response, err := http.DefaultClient.Do(request) if err != nil { panic(err.Error()) } defer response.Body.Close() if response.StatusCode != 200 { panic(err.Error()) } text, err := ioutil.ReadAll(response.Body) Json **************************************** Go 使用 json.Unmarshal 将 Json 数据映射到结构体上: .. code-block:: go var data []ReleaseData err = json.Unmarshal(jsonData, &data) if err != nil { panic(err.Error()) } for i := 0; i < len(data); i++ { release := data[i] assets := release.Assets for j := 0; j < len(assets); j++ { asset := assets[j] str := fmt.Sprintf("%v %v %v %v", release.Name, release.Date, asset.Name, asset.Url) fmt.Println(str) } } 其中结构体的定义为: .. code-block:: go type ReleaseAsset struct { Name string `json:"name"` URL string `json:"browser_download_url"` } type ReleaseData struct { Name string `json:"tag_name"` Date string `json:"published_at"` Assets []ReleaseAsset `json:"assets"` } 结构体的数据成员的名字首字母需要大写 .. seealso:: - `Go语言中处理json数据的方法-Golang-PHP中文网 `_ HTML 解析 **************************************** 一个简单的示例为: .. code-block:: go doc, err := goquery.NewDocumentFromReader(response.Body) if err != nil { panic(err.Error()) } doc.Find("tr>td>.comma-separated").First().Find("li").Each(func(i int, s *goquery.Selection) { Output(url, s.Text()) }) 限制连接数量 **************************************** Linux 对于程序允许打开的文件数量有限制,此限制可以通过 :command:`cat /proc/pid/limits | grep files | awk '{print $4}'` 查看,而程序已经打开的文件数量则可以通过 :command:`ls /dev/fd/ | wc -l` 查看 程序打开的套接字数量应当总是小于可用套接字数量 另外,go 会对套接字进行缓存,因此还需要限制连接池中可缓存的连接数量。 下面的代码可用于查询可用套接字数量,并设置缓存套接字数量。之所以 fileLimit 需要减二,是因为 - 下标是从 0 开始的 - 信号量在小于零时才会阻塞 .. code-block:: go var ( fileLimit = 1024 cmd = fmt.Sprintf(`cat /proc/%v/limits | grep files | awk '{print $4}'`, os.Getpid()) cmder = exec.Command("/bin/bash", "-c", cmd) ) if data, err := cmder.CombinedOutput(); err == nil { fileLimit, _ = strconv.Atoi(strings.ReplaceAll(string(data), "\n", "")) } cmder = exec.Command("/bin/bash", "-c", "ls /dev/fd/| wc -l") if data, err := cmder.CombinedOutput(); err == nil { if openedFiles, err := strconv.Atoi(strings.ReplaceAll(string(data), "\n", "")); err == nil { fileLimit -= openedFiles } } fileLimit -= 2 sem = lib.NewSemaphore(fileLimit) if transport, ok := http.DefaultTransport.(*http.Transport); ok { transport.MaxIdleConns = fileLimit transport.MaxIdleConnsPerHost = 0 transport.MaxConnsPerHost = fileLimit transport.DisableKeepAlives = true } .. seealso:: - `Golang 服务之坑:too many open files_Shanks-CSDN博客 `_ - `go HTTP配置参数MaxIdleConnsPerHost 和DisableKeepAlives - 简书 `_