在Go中使用超时时,添加tls.Dial
的最佳方法是什么?
我看到net
包有net.DialTimeout
,但不幸的是,tls
包没有相应的函数。
我想我应该使用context
或Dialer
来实现超时,但我不是围棋方面的专家,我找不到任何好的例子。
(1)我找到了tls.DialWithDialer
,但我不知道如何创建配置了超时的net.Dialer
。
func DialWithDialer(dialer *net.Dialer, network, addr string, config *Config) (*Conn, error)
(2)我还找到了tls.DialContext
,但我不知道如何使用它来实现超时。
func (d *Dialer) DialContext(ctx context.Context, network, addr string) (net.Conn, error)
(3)我认为可能可以使用net.DialTimeout
建立初始连接,然后升级连接并继续进行TLS握手,但我找不到任何示例说明如何进行此操作。
如有任何帮助或指导,将不胜感激。
下面是我的简单程序,它连接到服务器列表并打印一些关于证书链的信息。当服务器没有响应时,此程序挂起很长时间。我只想在10秒后暂停一下。
package main
import (
"bufio"
"crypto/tls"
"fmt"
"os"
)
func main() {
port := "443"
conf := &tls.Config{
InsecureSkipVerify: true,
}
s := bufio.NewScanner(os.Stdin)
for s.Scan() {
host := s.Text()
conn, err := tls.Dial("tcp", host+":"+port, conf)
if err != nil {
fmt.Println("Host:", host, "Dial:", err)
continue
}
defer conn.Close()
certs := conn.ConnectionState().PeerCertificates
for _, cert := range certs {
fmt.Println("Host:", host, "Issuer:", cert.Issuer)
}
}
}
发布于 2021-09-27 23:34:52
正如您在问题中提到的,有几种选择;使用DialContext
是一种常见的技术:
package main
import (
"bufio"
"context"
"crypto/tls"
"fmt"
"os"
"time"
)
func main() {
port := "443"
conf := &tls.Config{
InsecureSkipVerify: true,
}
s := bufio.NewScanner(os.Stdin)
for s.Scan() {
host := s.Text()
ctx, cancel := context.WithTimeout(context.Background(), 10 * time.Second)
d := tls.Dialer{
Config: conf,
}
conn, err := d.DialContext(ctx,"tcp", host+":"+port)
cancel() // Ensure cancel is always called
if err != nil {
fmt.Println("Host:", host, "Dial:", err)
continue
}
// warning: using defer in a loop may not have the expected result
// the connection will remain open until the function exists
defer conn.Close()
tlsConn := conn.(*tls.Conn)
certs := tlsConn.ConnectionState().PeerCertificates
for _, cert := range certs {
fmt.Println("Host:", host, "Issuer:", cert.Issuer)
}
}
}
使用上述方法可以相对简单地允许代码用户取消请求(接受context
,并在上面有context.Background()
的地方使用)。如果这对您不重要,那么在Dialer
中使用Timeout
就更简单了:
conn, err := tls.DialWithDialer(&net.Dialer{Timeout: 10 * time.Second}, "tcp", host+":"+port, conf)
if err != nil {
fmt.Println("Host:", host, "Dial:", err)
continue
}
certs := conn.ConnectionState().PeerCertificates
for _, cert := range certs {
fmt.Println("Host:", host, "Issuer:", cert.Issuer)
}
conn.Close()
https://stackoverflow.com/questions/69353996
复制相似问题