网络编程
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
}