网络编程

HTTP 请求

制作一个 http 请求需要用到 http 包,一个简单的示例如下:

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 数据映射到结构体上:

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)
    }
}

其中结构体的定义为:

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"`
}

结构体的数据成员的名字首字母需要大写

HTML 解析

一个简单的示例为:

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 对于程序允许打开的文件数量有限制,此限制可以通过 cat /proc/pid/limits | grep files | awk '{print $4}' 查看,而程序已经打开的文件数量则可以通过 ls /dev/fd/ | wc -l 查看

程序打开的套接字数量应当总是小于可用套接字数量

另外,go 会对套接字进行缓存,因此还需要限制连接池中可缓存的连接数量。

下面的代码可用于查询可用套接字数量,并设置缓存套接字数量。之所以 fileLimit 需要减二,是因为

  • 下标是从 0 开始的

  • 信号量在小于零时才会阻塞

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

}
Last moify: 2022-12-04 15:11:33
Build time:2025-07-18 09:41:42
Powered By asphinx