公告

微信

欢迎大家私信交流

Skip to content

网络编程

神马是网路

访问一个网站流程!

1.查询本地 hosts 文件

  • 本地解析:操作系统会首先检查本地的 hosts 文件,看看是否有对应的域名和 IP 地址的映射。如果找到匹配的条目,就直接使用这个 IP 地址。

2.DNS 解析

  • DNS 查询:如果 hosts 文件中没有找到对应的 IP 地址,操作系统会向配置的 DNS 服务器发送查询请求。
  • 递归查询:DNS 服务器会进行递归查询,可能需要向多个 DNS 服务器询问,直到找到正确的 IP 地址。
  • 缓存:DNS 服务器和本地系统都会缓存查询结果,以加速后续的解析过程。

3.建立 TCP 连接

  • TCP 封包:使用解析得到的 IP 地址和端口号(通常是 80 或 443),客户端会创建一个 TCP 套接字。
  • 三次握手:TCP 使用三次握手(SYN, SYN-ACK, ACK)来建立可靠的连接。

4.发送 HTTP 请求

  • HTTP 请求封包:一旦 TCP 连接建立成功,客户端会构建一个 HTTP 请求报文(例如,GET 请求),并通过 TCP 连接发送到服务器。
  • HTTPS 加密:如果使用 HTTPS,客户端和服务器之间会先进行 SSL/TLS 握手,协商加密方式和密钥,然后再发送加密的 HTTP 请求。

5.数据传输

  • 网络传输:数据包会通过网络层、链路层和物理层传输,经过多个路由器和交换机到达目标服务器。
  • 分片与重组:如果数据包过大,IP 层会进行分片,目标服务器会对分片进行重组。

6.服务器处理请求

  • 服务器响应:服务器接收到请求后,会进行处理(例如查询数据库、读取文件等),然后构建 HTTP 响应报文。
  • 发送响应:服务器通过相同的 TCP 连接将响应报文发送回客户端。

7.客户端接收响应

  • 接收数据:客户端接收到 HTTP 响应报文,解析其中的状态码、头部和主体内容。
  • 渲染页面:如果是浏览器,通常会解析 HTML 内容,下载并处理嵌入的资源(如 CSS、JavaScript、图片等),然后渲染页面。

8.关闭连接

  • 四次挥手:在数据传输完成后,TCP 连接会通过四次挥手(FIN, FIN-ACK, ACK, ACK)来关闭连接。

9.缓存与优化

  • 缓存机制:浏览器和代理服务器会缓存常用资源,以减少后续请求的延迟。
  • CDN 加速:使用内容分发网络(CDN)可以将内容缓存到离用户更近的服务器,进一步加速访问速度。

OSI模型

物数网传会表应

TCP编程

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

网络编程和TCP编程 遵守 CB 模型。

以上的四步:请求、读取、响应、处理

服务端

go
// 处理函数
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() {
    // 1. 监听端口
    listen, err := net.Listen("tcp", "127.0.0.1:20000")
    if err != nil {
        fmt.Println("listen failed, err:", err)
        return
    }
    for {
        // 2. 接收客户端请求建立连接
        conn, err := listen.Accept() // 建立连接
        if err != nil {
            fmt.Println("accept failed, err:", err)
            continue
        }
        // 3. 创建goroutine处理连接
        go process(conn) // 启动一个goroutine处理连接
    }
}

客户端

go
// 客户端
func main() {
    // 1. 建立与服务端的连接
    conn, err := net.Dial("tcp", "127.0.0.1:20000")
    if err != nil {
        fmt.Println("err :", err)
        return
    }

    // 3. 等待return时关闭连接
    defer conn.Close() // 关闭连接

    // 2. 进行数据的收发
    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]))
    }
}

UDP编程

UDP协议(User Datagram Protocol)中文名称是用户数据报协议,是OSI参考模型中一种无连接的传输层协议,不需要建立连接就能直接进行数据发送和接收,属于不可靠的、没有时序的通信,但是UDP协议的实时性比较好,通常用于视频直播相关领域。

遵守 CB模型

服务端

go
// 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
        }
    }
}

客户端

go
// 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)
}

HTTP编程

超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议。

它详细规定了浏览器和万维网(www服务器也就是web服务器)服务器之间互相通信的规则,通过因特网传送万维网文档的数据传送协议。

HTTP协议通常承载于TCP协议之上。

服务端

go
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("你好,码神之路"))
}

客户端

go
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
        }
    }
}

上次更新于: