首页 » 技术分享 » 【go语言 socket编程系列】net.DialTCP、net.DIalUDP与net.Dial

【go语言 socket编程系列】net.DialTCP、net.DIalUDP与net.Dial

 

【函数原型】

func DialTCP(network string, laddr, raddr *TCPAddr) (*TCPConn, error) 
func DialUDP(network string, laddr, raddr *UDPAddr) (*UDPConn, error)
func Dial(network, address string) (Conn, error)

DialTCP与DialUDP 的参数及返回比较相似,其中TCPConn与UDPConn的定义如下

分别在tcpsock.go 与udpsock.go文件中

// TCPConn is an implementation of the Conn interface for TCP network
// connections.
type TCPConn struct {
        conn
}
// UDPConn is the implementation of the Conn and PacketConn interfaces
// for UDP network connections.
type UDPConn struct {
        conn
}

而conn 在之前的文章中提到过,是定义在net.go中的一个文件描述符

type conn struct {
        fd *netFD
}

从上面可知,DIalTCP与DIalUDP返回的都是 conn类似的数据。

而func Dial(network, address string) (Conn, error) ,参数做了简化,返回结果是一个Conn类型。

Conn 属于接口类型,可以参考以前的文章【go语言 socket编程系列】Conn接口类型及简单服务器实现Read Write 和Close方法

即 conn类似的数据实现了Conn中的方法,

【net.Dial简介】

函数定义在源文件dial.go中,源码如下

func Dial(network, address string) (Conn, error) {
        var d Dialer
        return d.Dial(network, address)
}

简短两行代码

          第一行定义了一个 Dialer类型的数据。

          第二行 调用Dialer数据类型实现的Dial方法

先看Dialer类型数据,主要是一些选项,超时时间、取消链接之类的,后续详细展开。

type Dialer struct {
        Timeout time.Duration
        Deadline time.Time
        LocalAddr Addr
        DualStack bool
        FallbackDelay time.Duration
        KeepAlive time.Duration
        Resolver *Resolver
        Cancel <-chan struct{}
}

Dialer类型数据实现的Dial方法源码如下,在dial.go中

func (d *Dialer) Dial(network, address string) (Conn, error) {
    return d.DialContext(context.Background(), network, address)
}

仅仅是调用了d.DialContext 方法,这样做除了函数名看起来简洁外还没领悟到其他的好处~。

其源码如下,还没细看。

func (d *Dialer) DialContext(ctx context.Context, network, address string) (Conn, error) {
        if ctx == nil {
                panic("nil context")
        }
        deadline := d.deadline(ctx, time.Now())
        if !deadline.IsZero() {
                if d, ok := ctx.Deadline(); !ok || deadline.Before(d) {
                        subCtx, cancel := context.WithDeadline(ctx, deadline)
                        defer cancel()
                        ctx = subCtx
                }
        }
        if oldCancel := d.Cancel; oldCancel != nil {
                subCtx, cancel := context.WithCancel(ctx)
                defer cancel()
                go func() {
                        select {
                        case <-oldCancel:
                                cancel()
                        case <-subCtx.Done():
                        }
                }()
                ctx = subCtx
        }

        // Shadow the nettrace (if any) during resolve so Connect events don't fire for DNS lookups.
        resolveCtx := ctx
        if trace, _ := ctx.Value(nettrace.TraceKey{}).(*nettrace.Trace); trace != nil {
                shadow := *trace
                shadow.ConnectStart = nil
                shadow.ConnectDone = nil
                resolveCtx = context.WithValue(resolveCtx, nettrace.TraceKey{}, &shadow)
        }

        addrs, err := d.resolver().resolveAddrList(resolveCtx, "dial", network, address, d.LocalAddr)
        if err != nil {
                return nil, &OpError{Op: "dial", Net: network, Source: nil, Addr: nil, Err: err}
        }

        dp := &dialParam{
                Dialer:  *d,
                network: network,
                address: address,
        }
        var primaries, fallbacks addrList
        if d.DualStack && network == "tcp" {
                primaries, fallbacks = addrs.partition(isIPv4)
        } else {
                primaries = addrs
        }

        var c Conn
        if len(fallbacks) > 0 {
                c, err = dialParallel(ctx, dp, primaries, fallbacks)
        } else {
                c, err = dialSerial(ctx, dp, primaries)
        }
        if err != nil {
                return nil, err
        }

        if tc, ok := c.(*TCPConn); ok && d.KeepAlive > 0 {
                setKeepAlive(tc.fd, true)
                setKeepAlivePeriod(tc.fd, d.KeepAlive)
                testHookSetKeepAlive()
        }
        return c, nil
}

在dial.go中有个DialTimeout 函数,即带timeout参数。其实现代码如下,通过Dialer struct的 timeout实现

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

【net.Dial用法】

函数调用方法很简单,源码注释中直接有例子

Dial("tcp", "golang.org:http")
Dial("tcp", "192.0.2.1:http")
Dial("tcp", "198.51.100.1:80")
Dial("udp", "[2001:db8::1]:domain")
Dial("udp", "[fe80::1%lo0]:53")
Dial("tcp", ":80")
 

转载自原文链接, 如需删除请联系管理员。

原文链接:【go语言 socket编程系列】net.DialTCP、net.DIalUDP与net.Dial,转载请注明来源!

0