网络编程 (net包)
大约 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())
}
}
启动流程
连接流程
- 先启动服务器。
go run server/main.go
- 再启动客户端。
go run client/main.go
(由于服务端开了for循环,这里可以启动多个客户端) - 然后查看双方的控制台输出是否正常 (正常连接)
发送 (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]))
}
}