跳至主要內容

网络编程 (net包)

LincZero大约 3 分钟

网络编程 (net包)

(需先学习协程、管道、select case 语法)

Go的网络编程所需全部都在net包下

网络编程的引入

略。讲了一下ISO,L4层 (IP+Port),TCP。都是很基础的东西

net包

net包提供网络I/O接口,包括TCP/IP、UDP、域名解析、Unix域Socket等。详见:studygolang.com.pkgdoc

大部分情况下只需要使用:

  • 客户端:Dial
  • 服务端:Listen
  • Accept函数提供的基本接口,以及Conn和Listener接口

crypto/tls包

除了net包,crypto/tls包也提供了相同的接口和类似的Dial和Listen函数

TCP编程

创建客户端 (net包.Dial)

原型

/**
 * @param network 协议
 *   - tcp、tcp4、tcp6、udp、udp4、udp6、ip、ip4、ip6、unix、unixgram、unixpacket
 * @param string 根据协议的不同,格式可能不同
 *   - 例如:Dial("tcp", "12.34.56.78:80")
 */
func Dial(network, address string) (Conn, error)

案例

unit13/demo01/client/main.go

package main
import(
	"fmt"
    "net"
)

func main() {
    fmt.Println(">>> 客户端")
    
    // 客户端连接
    conn, err := net.Dial("tcp", "127.0.0.1:8888")
    if err != nil {
        fmt.Println("客户端连接失败, err:", err)
        return
    }
    fmt.Println("客户端连接成功, conn:", conn)
}

创建服务端 (net包.Listen、listen对象.Accept)

原型

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

案例

unit13/demo01/server/main.go

package main
import(
	"fmt"
    "net"
)

func main() {
    fmt.Println(">>> 服务端")
    
    // 服务端监听
    listen, err := net.Listen("tcp", "127.0.0.1:8888")
    if err != nil {	// 监听失败
        fmt.Println("服务端监听失败, err:", err)
        return
    }
    fmt.Println("服务端监听成功, listen:", listen)
    
    for {
        // 服务端连接
        conn, err2 := listen.Accept()
        if err2 != nil {
            fmt.Println("服务端连接失败, err:", err)
            return
        }
        fmt.Printf("服务端连接成功, conn:%v, 客户端地址:%v\n", conn, conn.RemoteAddr().String())
    }
}

启动流程

连接流程

  1. 先启动服务器。go run server/main.go
  2. 再启动客户端。go run client/main.go (由于服务端开了for循环,这里可以启动多个客户端)
  3. 然后查看双方的控制台输出是否正常 (正常连接)

发送 (conn对象.Write、conn对象.Read)

客户端:

unit13/demo01/client/main.go

package main
import(
	"fmt"
    "net"
    "bufio"
    "os"
)

func main() {
    // 客户端连接
    fmt.Println(">>> 客户端")
    conn, err := net.Dial("tcp", "127.0.0.1:8888")
    if err != nil {
        fmt.Println("客户端连接失败, err:", err)
        return
    }
    fmt.Println("客户端连接成功, conn:", conn)
    
    // 获取终端输入
    bufio.NewReader(os.Stdin)	// os.Stdio表示标准输入
    str, err := reader.ReadString('\n')
    if err != nil {
        fmt.Println("终端输入失败, err:", err)
        return
    }
    
    // 客户端发送
    n, err := conn.Write([]byte(str))
    if err != nil {
        fmt.Println("连接失败, err:", err)
        return
    }
    fmt.Printf("发送成功,发送了%d字节,并退出\n", n)
}

服务端:

unit13/demo01/server/main.go

package main
import(
	"fmt"
    "net"
)

func main() {
    fmt.Println(">>> 服务端")
    
    // 服务端监听
    listen, err := net.Listen("tcp", "127.0.0.1:8888")
    if err != nil {	// 监听失败
        fmt.Println("服务端监听失败, err:", err)
        return
    }
    fmt.Println("服务端监听成功, listen:", listen)
    
    // 一对多
    for {
        // 服务端连接
        conn, err2 := listen.Accept()
        if err2 != nil {
            fmt.Println("服务端连接失败, err:", err)
            continue
        }
        fmt.Printf("服务端连接成功, conn:%v, 客户端地址:%v\n", conn, conn.RemoteAddr().String())
        
        // 准备一个协程,每个协程对应一个客户端
        go process(conn)
    }
}

func process(conn net.Conn) {
    defer conn.Close()
    for {
        buf := make([]byte, 1024)	// 创建一个切片,存储读取的数据
        
        n, err := conn.Read(buf)
        if err != nil {
            return
        }
        fmt.Prinln("服务端接收:", string(buf[0:n]))
    }
}