net包之dial撥號和listen監聽


今為止我們已經區分TCP和UDP API的不同,使用例子DialTCP和DialUDP分別返回一個TCPConn和 UDPConn。Conn類型是一個接口,TCPConn和UDPConn實現了該接口。在很大程度上,你可以通過該接口處理而不是用這兩種類型。

Dial(network, address string) (Conn, error)

net可以是"tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only), "udp", "udp4" (IPv4-only), "udp6" (IPv6-only), "ip", "ip4" (IPv4-only)和"ip6" (IPv6-only)任何一種。它將返回一個實現了Conn接口的類型。注意此函數接受一個字符串而不是raddr地址參數,因此,使用此程序可避免的地址類型。

使用該函數需要對程序輕微的調整。例如, 前面的程序從一個Web頁面獲取HEAD信息可以被重新寫為

一個客戶端的例子

package main

import (
        "bytes"
        "fmt"
        "io"
        "net"
        "os"
)

func main() {
        if len(os.Args) != 2 {
                fmt.Fprintf(os.Stderr, "Usage: %s host:port", os.Args[0])
                os.Exit(1)
        }
        service := os.Args[1]

        conn, err := net.Dial("tcp", service)
        checkError(err)

        _, err = conn.Write([]byte("HEAD / HTTP/1.0\r\n\r\n"))
        checkError(err)

        result, err := readFully(conn)
        checkError(err)

        fmt.Println(string(result))

        os.Exit(0)
}

func checkError(err error) {
        if err != nil {
                fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())
                os.Exit(1)
        }
}

func readFully(conn net.Conn) ([]byte, error) {
        defer conn.Close()

        result := bytes.NewBuffer(nil)
        var buf [512]byte
        for {
                n, err := conn.Read(buf[0:])
                result.Write(buf[0:n])
                if err != nil {
                        if err == io.EOF {
                                break
                        }
                        return nil, err
                }
        }
        return result.Bytes(), nil
}

Listen(net, laddr string) (Listener, error)

返回一個實現Listener接口的對象.net參數可以為"tcp", "tcp4", "tcp6", "unix" 或者 "unixpacket".

func Listen(net, laddr string) (Listener, error) {
	la, err := resolveAddr("listen", net, laddr, noDeadline)
	if err != nil {
		return nil, err
	}
	switch la := la.(type) {
	case *TCPAddr:
		return ListenTCP(net, la)    //監聽TCP
	case *UnixAddr:
		return ListenUnix(net, la)   //監聽Unix
	}
	return nil, UnknownNetworkError(net)
}

看個服務端的例子

package main

import (
        "fmt"
        "net"
        "os"
)

func main() {

        service := ":1200"
        listener, err := net.Listen("tcp", service)
        checkError(err)

        for {
                conn, err := listener.Accept()
                if err != nil {
                        continue
                }
                go handleClient(conn)
        }
}

func handleClient(conn net.Conn) {
        defer conn.Close()

        var buf [512]byte
        for {
                n, err := conn.Read(buf[0:])
                if err != nil {
                        return
                }
                _, err2 := conn.Write(buf[0:n])
                if err2 != nil {
                        return
                }
        }
}

func checkError(err error) {
        if err != nil {
                fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())
                os.Exit(1)
        }
}

ListenPacket(net, laddr string) (PacketConn, error)

如果你想寫一個UDP服務器, 有一個PacketConn的接口,和實現了該接口的方法ListenPacket.這里net參數為:udp", "udp4", "udp6", "ip", "ip4", "ip6"或者"unixgram"

func ListenPacket(net, laddr string) (PacketConn, error) {
	la, err := resolveAddr("listen", net, laddr, noDeadline)
	if err != nil {
		return nil, err
	}
	switch la := la.(type) {
	case *UDPAddr:
		return ListenUDP(net, la)
	case *IPAddr:
		return ListenIP(net, la)
	case *UnixAddr:
		return ListenUnixgram(net, la)
	}
	return nil, UnknownNetworkError(net)
}

Dialer

type Dialer struct {
	Timeout time.Duration
	Deadline time.Time
	LocalAddr Addr
}

DialTimeout(network, address string, timeout time.Duration) (Conn, error)

設置deadline,為time.Now().Add(d.Timeout)

關於如何在網絡上發送數據

很顯然net包.提供了基本上的建立客戶端與服務端的函數

  • 這些函數會建立一個conn或者監聽器,同時每個分別都擁有netFD類型參數
  • netFD類型抽象了各個平台,對網絡的操作
  • netFD通過各個操作系統特有的socket接口在網絡上進行發送數據包.所以是跨平台的


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM