网络编程
神马是网路
访问一个网站流程!
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
}
}
}