net包

所需的网络编程都在net包下
大部分使用者只需要Dial Listen Accpet函数提供的基本接口;以及相关的Conn Listener
crypto/tls包提供了相同的接口和类似的DialListen函数.

创建客户端

语法:
func Dial(network ,address string) (Conn,err)
地址格式:

1
2
3
4
Dial("tcp", "12.34.56.78:80")
Dial("tcp", "google.com:http")
Dial("tcp", "[2001:db8::1]:http")
Dial("tcp", "[fe80::1%lo0]:80")

对IP网络,network必须是”ip”、”ip4”、”ip6”后跟冒号和协议号或者协议名,地址必须是IP地址字面值。

1
2
Dial("ip4:1", "127.0.0.1")
Dial("ip6:ospf", "::1")

demo

1
2
3
4
5
6
7
8
9
// 创建一个客户端
// 调用Dial函数 协议 地址
conn, err := net.Dial("tcp", "127.0.0.1:10808")
if err != nil {
fmt.Println("客户端连接失败", err)
return
}
fmt.Println("连接成功:", conn)
fmt.Println("exit...")

通过客户端终端向服务器发送数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 通过终端输入信息
reader := bufio.NewReader(os.Stdin) // os.Stdin 代表终端输入
//从终端读取一行用户输入的数据
str, err := reader.ReadString('\n')
if err != nil {
fmt.Println("读取用户输入的信息失败:", err)
return
}
// 向服务端发送数据 n是发送了多少个字节
n, err := conn.Write([]byte(str))
if err != nil {
fmt.Println("向服务端发送数据失败:", err)
}
fmt.Printf("向服务端发送了%d个字节的数据\n", n)

创建服务器端

Listener是一个用于面向流的网络协议的公用的网络监听器接口.多个线程可能会同时调用一个listener的方法.
Listener接口例子:

1
2
3
4
5
type Listener interface{
Addr() Addr
Accept() (c Conn, err error)
Close() error
}

demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
fmt.Println("启动服务器端tcp")
listen, err := net.Listen("tcp", ":8888")
if err != nil {
fmt.Println("监听失败:", err)
return
}
fmt.Println("监听成功:", listen)
// 持续监听
for {
// 等待客户端连接
conn, err := listen.Accept()
if err != nil {
fmt.Println("监听失败:",err)
continue
}
// go poress()
fmt.Println("conn:", conn)
}

接收来自客户端发送的数据

需要再上面代码的for中添加一个go协程
go poress()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 把连接传进来
func poress(conn net.Conn) {
// 用完就关闭这个连接
defer conn.Close()
// 持续监听客户端发来的数据
for {
// 创建一个切片 用来存储输入来的数据
buf := make([]byte, 1024)

// 从conn连接中读取数据: n是多少个字节
n, err := conn.Read(buf) // 把conn中的数据存入 buf中
if err != nil {
return
}
// 把[]byte类型强制转换成string类型,转换之前可能buf长度没有很长 所以进行截取操作 n是传输了多少个字节
fmt.Println("读取到来自客户端的数据:", string(buf[0:n]))
}
}
  • 创建客户端
  • 创建服务端

创建客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
import (
"encoding/json"
"fmt"
"net"
)

// tcp/client/main.go

// 客户端
func tcpClient() {
conn, err := net.Dial("tcp", "127.0.0.1:2023")
if err != nil {
fmt.Println("拨号失败 :", err)
return
}
defer conn.Close() // 关闭连接
//阻塞 防止断开
for {
mes := struct {
UserName string
Mes string
}{
UserName: "用户1",
}
fmt.Println("请输入要发送的内容:")
//接收到的字符串存储到mes中
fmt.Scanf("%s\n", &mes.Mes)
if mes.Mes == "" {
fmt.Println("字符串为空")
continue
}
if mes.Mes == "exit" {
fmt.Println("退出程序")
return
}
//开始发消息
//需要发送的是byte切片
//1.效率比较低
// data, _ := json.Marshal(&mes) //为了性能好传地址 &
// n, err := conn.Write(data) //write发送消息 read接收消息
// if err != nil {
// fmt.Println("发送失败")
// return
// }
// fmt.Printf("成功发送了%v个字节\n", n)
//2.高效一些
err = json.NewEncoder(conn).Encode(&mes)
if err != nil {
fmt.Println("发送失败")
return
}
}
}

创建服务端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
import (
"encoding/json"
"fmt"
"io"
"net"
)

func tcpServer() {
listen, err := net.Listen("tcp", ":2023")
if err != nil {
fmt.Println("监听失败:", err)
return
}
defer listen.Close()
for {
fmt.Println("主进程等待客户端连接...")
conn, err := listen.Accept()
if err != nil {
fmt.Println("接听失败", err)
continue
}
//协程
go func(conn net.Conn) {
fmt.Println("一个客户端协程已开启")
defer conn.Close()
for {

// //1.笨办法 byte切片接收
// buf := make([]byte, 4096) //缓冲区
// n, err := conn.Read(buf) //n是读到多少个切片
// if err == io.EOF {
// fmt.Println("客户端退出")
// return
// }
// if err != nil {
// fmt.Println("读取失败", err)
// return
// }
// mes := struct {
// UserName string
// Mes string
// }{}
// json.Unmarshal(buf[:n], &mes)

//2.更好的写法
mes := struct {
UserName string
Mes string
}{}
err := json.NewDecoder(conn).Decode(&mes)
if err == io.EOF {
fmt.Println("客户端退出")
return
}
if err != nil {
fmt.Println("读取失败", err)
return
}
fmt.Printf("%v说:%v\n", mes.UserName, mes.Mes)
}
}(conn)
}
}