有時須要指定網絡通訊時本地使用的IP地址和端口號。網絡
在Go語言中可經過定義 Dialer 中LocalAddr 成員實現。 Dialer結構定義以下:tcp
// A Dialer contains options for connecting to an address. // // The zero value for each field is equivalent to dialing // without that option. Dialing with the zero value of Dialer // is therefore equivalent to just calling the Dial function. type Dialer struct { ... // LocalAddr is the local address to use when dialing an // address. The address must be of a compatible type for the // network being dialed. // If nil, a local address is automatically chosen. LocalAddr Addr }
Addr是接口類型,其定義以下:測試
// Addr represents a network end point address. // // The two methods Network and String conventionally return strings // that can be passed as the arguments to Dial, but the exact form // and meaning of the strings is up to the implementation. type Addr interface { Network() string // name of the network (for example, "tcp", "udp") String() string // string form of address (for example, "192.0.2.1:25", "[2001:db8::1]:80") }
目前實現Addr接口的類型而且被net 庫支持的類型 包括:TCPAddr、UDPAddr、IPAddr。ui
下面經過代碼演示如何指定client 使用的IP和端口號。spa
例子中使用TCPAddr 類型。code
client
package main import ( "bufio" "fmt" "net" "os" "time" ) func DialCustom(network, address string, timeout time.Duration, localIP []byte, localPort int)(net.Conn,error) { netAddr := &net.TCPAddr{Port:localPort} if len(localIP) != 0 { netAddr.IP = localIP } fmt.Println("netAddr:", netAddr) d := net.Dialer{Timeout: timeout, LocalAddr: netAddr} return d.Dial(network, address) } func main() { serverAddr := "172.20.22.160:8080" // 172.28.0.180 //localIP := []byte{0xAC, 0x1C, 0, 0xB4} // 指定IP localIP := []byte{} // any IP,不指定IP localPort := 9001 // 指定端口 conn, err := DialCustom("tcp", serverAddr, time.Second*10, localIP,localPort) if err != nil { fmt.Println("dial failed:", err) os.Exit(1) } defer conn.Close() buffer := make([]byte, 512) reader := bufio.NewReader(conn) n, err2 := reader.Read(buffer) if err2 != nil { fmt.Println("Read failed:", err2) return } fmt.Println("count:", n, "msg:", string(buffer)) select{} }
server
package main import ( "fmt" "net" "log" ) func main() { addr := "0.0.0.0:8080" tcpAddr, err := net.ResolveTCPAddr("tcp",addr) if err != nil { log.Fatalf("net.ResovleTCPAddr fail:%s", addr) } listener, err := net.ListenTCP("tcp", tcpAddr) if err != nil { log.Fatalf("listen %s fail: %s", addr, err) } else { log.Println("rpc listening", addr) } for { conn, err := listener.Accept() if err != nil { log.Println("listener.Accept error:", err) continue } go handleConnection(conn) } } func handleConnection(conn net.Conn) { //defer conn.Close() var buffer []byte = []byte("You are welcome. I'm server.") n, err := conn.Write(buffer) if err != nil { fmt.Println("Write error:", err) } fmt.Println("send:", n) fmt.Println("connetion end") }
測試
啓動client,只指定端口orm
$ ./client netAddr: :9001 count: 28 msg: You are welcome. I'm server.
啓動client,指定IP,Portserver
$ ./client netAddr: 172.28.172.180:9001 count: 28 msg: You are welcome. I'm server
server輸出接口
./sever 2018/06/19 18:15:41 rpc listening 0.0.0.0:8080 send: 28 connetion end
查看鏈接rpc
$ netstat -anp | grep 8080 tcp 0 0 :::8080 :::* LISTEN 27328/./server tcp 0 0 ::ffff:172.20.22.160:8080 ::ffff:172.28.0.180:9001 ESTABLISHED 27328/./server
從測試結果看,能夠成功指定IP和端口。