网络编程
1. 什么是网络?
当我们访问一个网站时,发生了什么?
通过上面的流程,我们知道了这么几件事:
- 所有的网络设备是通过一根线连接在一起的
- 全球所有的网络设备共同组成了一张大网,这个网叫做广域网,俗称互联网(Internet)
- 网络设置之间进行通信(就是传输数据),需要一种规则,这种规则就叫做协议
- 每个网络设备都有一个IP地址
这里,我们需要了解一个知识,有广域网(WAN),自然就有局域网(LAN),局域网是小范围内的网络,典型的就是家庭网络或者公司网络
互联网的核心就是“互联网协议”,为了实现统一的标准,定义了OSI模型,全名 “开放式系统互联通信参考模型”。
本质上整个互联网是为了通信而生,在这个通信模型中,有两个重要的协议,TCP(传输控制协议)和IP(网际协议)协议,我们称之为TCP/IP协议。
TCP/IP
提供点对点的连接机制,将数据应该如何封装、定址、传输、路由以及在目的地如何接收,都加以标准化。它将软件通信过程抽象化为四个抽象层
。
我们在看看电脑的硬件组成
- 一个插到 I/O 总线扩展槽的适配器提供了到网络的物理接口。
- 从网络上接收到的数据从适配器经过 I/O 和内存总线复制到内存,通常是通过 DMA 传送。
- 数据也能从内存复制到网络。
从硬件和软件角度看两台网络设备之间的通信
- 套接字接口是对TCP/IP协议的抽象,屏蔽了协议细节,对外提供统一的接口
- 套接字位于应用层和传输层之间,供应用层调用。
网络编程就是基于各种协议(主要是TCP/IP)使数据能在网络设备之间进行传输和通信。
2. TCP编程
TCP(Transmission Control Protocol) 即传输控制协议,是一种面向连接的、可靠的、基于字节流的传输层(Transport layer)通信协议。
网络编程是基于
客户端-服务端编程模型
一个客户端—服务器事务由以下四步组成:
- 当一个客户端需要服务时,它向服务器发送一个请求,发起一个事务。例如,当 Web 浏览器需要一个文件时,它就发送一个请求给 Web 服务器。
- 服务器收到请求后,解释它,并以适当的方式操作它的资源。例如,当 Web 服务器收到浏览器发出的请求后,它就读一个磁盘文件。
- 服务器给客户端发送一个响应,并等待下一个请求。例如,Web 服务器将文件发送回客户端。
- 客户端收到响应并处理它。例如,当 Web 浏览器收到来自服务器的一页后,就在屏幕上显示此页。
TCP编程同样遵循
客户端-服务端编程模型
TCP服务端
多个客户端可以同时连接一个服务端,一个客户端连接,可以开一个协程处理,从而达到高效处理的结果,这也是Golang语言擅长的地方。
TCP服务端程序的处理流程:
- 监听端口
- 接收客户端请求建立连接
- 创建goroutine处理连接。
// 处理函数 func process(conn net.Conn) { defer conn.Close() // 关闭连接 for { reader := bufio.NewReader(conn) var buf [128]byte n, err := reader.Read(buf[:]) // 读取数据 if err != nil { fmt.Println("read from client failed, err:", err) break } recvStr := string(buf[:n]) fmt.Println("收到client端发来的数据:", recvStr) conn.Write([]byte(recvStr)) // 发送数据 } } func main() { listen, err := net.Listen("tcp", "127.0.0.1:20000") if err != nil { fmt.Println("listen failed, err:", err) return } for { conn, err := listen.Accept() // 建立连接 if err != nil { fmt.Println("accept failed, err:", err) continue } go process(conn) // 启动一个goroutine处理连接 } }
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
32TCP客户端
一个TCP客户端进行TCP通信的流程如下:
- 建立与服务端的连接
- 进行数据收发
- 关闭连接
// 客户端 func main() { conn, err := net.Dial("tcp", "127.0.0.1:20000") if err != nil { fmt.Println("err :", err) return } defer conn.Close() // 关闭连接 inputReader := bufio.NewReader(os.Stdin) for { input, _ := inputReader.ReadString('\n') // 读取用户输入 inputInfo := strings.Trim(input, "\r\n") if strings.ToUpper(inputInfo) == "Q" { // 如果输入q就退出 return } _, err = conn.Write([]byte(inputInfo)) // 发送数据 if err != nil { return } buf := [512]byte{} n, err := conn.Read(buf[:]) if err != nil { fmt.Println("recv failed, err:", err) return } fmt.Println(string(buf[: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
3. UDP编程
UDP协议
(User Datagram Protocol)中文名称是用户数据报协议,是OSI(Open System Interconnection,开放式系统互联)参考模型中一种无连接的传输层协议,不需要建立连接就能直接进行数据发送和接收,属于不可靠的、没有时序的通信,但是UDP协议的实时性比较好,通常用于视频直播相关领域。
UDP编程同样遵循
客户端-服务端编程模型
UDP服务端
// UDP server端 func main() { listen, err := net.ListenUDP("udp", &net.UDPAddr{ IP: net.IPv4(0, 0, 0, 0), Port: 30000, }) if err != nil { fmt.Println("listen failed, err:", err) return } defer listen.Close() for { var data [1024]byte n, addr, err := listen.ReadFromUDP(data[:]) // 接收数据 if err != nil { fmt.Println("read udp failed, err:", err) continue } fmt.Printf("data:%v addr:%v count:%v\n", string(data[:n]), addr, n) _, err = listen.WriteToUDP(data[:n], addr) // 发送数据 if err != nil { fmt.Println("write to udp failed, err:", err) continue } } }
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
26UDP客户端
// UDP 客户端 func main() { socket, err := net.DialUDP("udp", nil, &net.UDPAddr{ IP: net.IPv4(0, 0, 0, 0), Port: 30000, }) if err != nil { fmt.Println("连接服务端失败,err:", err) return } defer socket.Close() sendData := []byte("Hello server") _, err = socket.Write(sendData) // 发送数据 if err != nil { fmt.Println("发送数据失败,err:", err) return } data := make([]byte, 4096) n, remoteAddr, err := socket.ReadFromUDP(data) // 接收数据 if err != nil { fmt.Println("接收数据失败,err:", err) return } fmt.Printf("recv:%v addr:%v count:%v\n", string(data[:n]), remoteAddr, 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
4. HTTP编程
- 超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议,它详细规定了浏览器和万维网(www服务器也就是web服务器)服务器之间互相通信的规则,通过因特网传送万维网文档的数据传送协议
- HTTP协议通常承载于TCP协议之上
HTTP编程同样遵循
客户端-服务端编程模型
HTTP服务端
package main import ( "fmt" "net/http" ) func main() { //http://127.0.0.1:8000/go // 单独写回调函数 http.HandleFunc("/go", myHandler) // addr:监听的地址 // handler:回调函数 http.ListenAndServe("127.0.0.1:8000", nil) } // handler函数 func myHandler(w http.ResponseWriter, r *http.Request) { fmt.Println(r.RemoteAddr, "连接成功") // 请求方式:GET POST DELETE PUT UPDATE fmt.Println("method:", r.Method) // /go fmt.Println("url:", r.URL.Path) fmt.Println("header:", r.Header) fmt.Println("body:", r.Body) // 回复 w.Write([]byte("你好,码神之路")) }
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
28HTTP客户端
package main import ( "fmt" "io" "net/http" ) func main() { //resp, _ := http.Get("http://www.baidu.com") //fmt.Println(resp) resp, _ := http.Get("http://127.0.0.1:8000/go") defer resp.Body.Close() // 200 OK fmt.Println(resp.Status) fmt.Println(resp.Header) buf := make([]byte, 1024) for { // 接收服务端信息 n, err := resp.Body.Read(buf) if err != nil && err != io.EOF { fmt.Println(err) return } else { fmt.Println("读取完毕") res := string(buf[:n]) fmt.Println(res) break } } }
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