网络编程

1. 什么是网络?

当我们访问一个网站时,发生了什么?

网络

通过上面的流程,我们知道了这么几件事:

  • 所有的网络设备是通过一根线连接在一起的
  • 全球所有的网络设备共同组成了一张大网,这个网叫做广域网,俗称互联网(Internet)
  • 网络设置之间进行通信(就是传输数据),需要一种规则,这种规则就叫做协议
  • 每个网络设备都有一个IP地址

internet

这里,我们需要了解一个知识,有广域网(WAN),自然就有局域网(LAN),局域网是小范围内的网络,典型的就是家庭网络或者公司网络

lan

互联网的核心就是“互联网协议”,为了实现统一的标准,定义了OSI模型,全名 “开放式系统互联通信参考模型”。

img

本质上整个互联网是为了通信而生,在这个通信模型中,有两个重要的协议,TCP(传输控制协议)和IP(网际协议)协议,我们称之为TCP/IP协议。

TCP/IP 提供点对点的连接机制,将数据应该如何封装、定址、传输、路由以及在目的地如何接收,都加以标准化。它将软件通信过程抽象化为四个抽象层

image-20220116003106034

我们在看看电脑的硬件组成

image-20240326232310885

  • 一个插到 I/O 总线扩展槽的适配器提供了到网络的物理接口。
  • 从网络上接收到的数据从适配器经过 I/O 和内存总线复制到内存,通常是通过 DMA 传送。
  • 数据也能从内存复制到网络。

从硬件和软件角度看两台网络设备之间的通信

image-20240326232537821

  • 套接字接口是对TCP/IP协议的抽象,屏蔽了协议细节,对外提供统一的接口

img

  • 套接字位于应用层和传输层之间,供应用层调用。

网络编程就是基于各种协议(主要是TCP/IP)使数据能在网络设备之间进行传输和通信。

2. TCP编程

TCP(Transmission Control Protocol) 即传输控制协议,是一种面向连接的、可靠的、基于字节流的传输层(Transport layer)通信协议。

网络编程是基于客户端-服务端编程模型

image-20240331225409587

一个客户端—服务器事务由以下四步组成:

  1. 当一个客户端需要服务时,它向服务器发送一个请求,发起一个事务。例如,当 Web 浏览器需要一个文件时,它就发送一个请求给 Web 服务器。
  2. 服务器收到请求后,解释它,并以适当的方式操作它的资源。例如,当 Web 服务器收到浏览器发出的请求后,它就读一个磁盘文件。
  3. 服务器给客户端发送一个响应,并等待下一个请求。例如,Web 服务器将文件发送回客户端。
  4. 客户端收到响应并处理它。例如,当 Web 浏览器收到来自服务器的一页后,就在屏幕上显示此页。

TCP编程同样遵循客户端-服务端编程模型

  • TCP服务端

    多个客户端可以同时连接一个服务端,一个客户端连接,可以开一个协程处理,从而达到高效处理的结果,这也是Golang语言擅长的地方。

    TCP服务端程序的处理流程:

    1. 监听端口
    2. 接收客户端请求建立连接
    3. 创建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
    32
  • TCP客户端

    一个TCP客户端进行TCP通信的流程如下:

    1. 建立与服务端的连接
    2. 进行数据收发
    3. 关闭连接
    // 客户端
    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
    26
  • UDP客户端

    // 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
    28
  • HTTP客户端

    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