1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > Go 语言网络编程系列(二)— Socket 编程入门:Dial 函数底层实现及超时处理

Go 语言网络编程系列(二)— Socket 编程入门:Dial 函数底层实现及超时处理

时间:2022-10-03 02:47:40

相关推荐

Go 语言网络编程系列(二)— Socket 编程入门:Dial 函数底层实现及超时处理

Dial 函数的底层调用

在上篇教程中,我们介绍了 Go 语言中可以通过Dial()函数建立网络连接。实际上,Dial()函数是对dialTCP()、dialUDP()、dialIP()和dialUnix()的封装,这可以通过追溯Dial()函数的源码看到,底层真正建立连接是通过dialSingle()函数完成的:

dialSingle()函数通过从传入参数中获取网络协议类型调用对应的连接建立函数并返回连接对象。再往下追溯,可以看到这些底层函数最终都调用了 syscall 包的Socket()函数与对应平台操纵系统的 Socket API 交互实现网络连接的建立,针对不同的通信协议,建立不同的连接类型:

其中domain代表通信域,支持 IPv4、IPv6 和 Unix,对应的常量值分别是syscall.AF_INET、syscall.AF_INET6和syscall.AF_UNIX。

注:IPv4 和 IPv6 分别代表 IP 协议网络的第四版和第六版,Unix 指的是类 Unix 操作系统中特有的通信域,在装有此类操作系统的同一台计算机中,应用程序可以基于此域建立 socket 连接。

typ代表 Socket 的类型,比如 TCP 对应的 Socket 类型常量是syscall.SOCK_STREAM(面向连接通信),UDP 对应的 Socket 类型常量是syscall.SOCK_DGRAM(面向无连接通信),此外还支持syscall.SOCK_RAW和syscall.SOCK_SEQPACKET两种类型,SOCK_RAW其实就是原始的 IP 协议包,SOCK_SEQPACKET与SOCK_STREAM类似,都是面向连接的,只不过前者有消息边界,传输的是数据包,而不是字节流。通常,我们使用SOCK_STREAM和SOCK_DGRAM居多。

最后一个参数proto表示通信协议,一般默认为0,因为该值可以通过前两个参数判断得出,比如,前两个参数值分别为syscall.AF_INET和syscall.SOCK_DGRAM的时候,会选择 UDP 作为通信协议,前两个参数值分别为syscall.AF_INET6和syscall.SOCK_STREAM时,会选择 TCP 作为通信协议。

当然,我们在 Go 语言中编写网络程序时,完全不用关心这些底层的实现细节,只需要调用Dial函数并传入对应的参数就可以了。

网络超时处理

网络超时包含在多个环节中,比如连接超时、请求超时和响应超时,我们先来看连接超时。

1、连接超时

在使用Dial函数建立网络连接时,可以使用net包提供的DialTimeout函数主动传入额外的超时参数来建立连接,该函数原型如下:

func DialTimeout(network, address string, timeout time.Duration) (Conn, error) { d := Dialer{Timeout: timeout} return d.Dial(network, address)}

和Dial函数调用一样,只是设置了超时字段而已,如果使用Dial函数,默认会通过操作系统提供的机制来处理连接超时,对于 TCP 连接,通常是 3 分钟左右,这对我们的程序来说,可能太长了,这个时候,就可以通过DialTimeout来建立连接,以上篇教程编写的示例代码tcp.go为例,如果请求国外被封的域名,比如,程序可能长时间没有反应,将建立网络连接的代码调整如下:

// 建立网络连接conn, err := net.DialTimeout("tcp", service, 3 * time.Second)

再次请求,3 秒后就会返回超时错误退出:

2、请求和响应超时

使用Dial或DialTimeout函数建立网络连接成功之后,都会返回net.Conn对象,然后我们就可以在该对象上进行读写操作实现请求和响应,关于这一部分的超时,可以通过Conn提供的以下三个方法来设置:

SetDeadline(t time.Time) errorSetReadDeadline(t time.Time) errorSetWriteDeadline(t time.Time) error

我们可以通过SetDeadline设置统一的读写超时时间,也可以通过SetReadDeadline和SetWriteDeadline分别设置读超时和写超时。注意这三个方法传入的都是绝对时间值,而不是相对时间长度:

// 设置读写超时时间err = conn.SetDeadline(time.Now().Add(5 * time.Second))checkError(err)

更多工具函数

此外,net 包中还提供了一系列的工具函数,合理地使用这些函数可以有效提高开发效率,并且更好地保证程序质量。

比如,可以通过ParseIP函数验证 IP 地址的有效性:

func net.ParseIP()

通过IPv4Mask创建子网掩码:

func IPv4Mask(a, b, c, d byte) IPMask

通过DefaultMask获取默认子网掩码:

func (ip IP) DefaultMask() IPMask

以及根据域名查找对应 IP 地址:

func ResolveIPAddr(net, addr string) (*IPAddr, error) func LookupHost(name string) (cname string, addrs []string, err error)

等等,更多工具函数请参考net 包文档。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。