Java转Go全过程04-网络编程部分

Java开发已经是红海一片,面临着35岁危机的压力,需要适时的调整策略,以应对可能会出现的不确定性。毕竟,命运掌握在自己手里,比掌握在公司手里 安全感会强很多。

尝试的其中一条路即为:Java转Go,海外开发web3相关,也有其他的尝试,会开辟相应的专栏收录。

针对每一个部分,都会在最后准备练习题,可以多做几遍,用于巩固知识,多动手!

后续golang语言学习过程中产生的全部内容,会发布在 web3这个专栏中。

Go语言基础快速突破[网络编程](1-2周)

1. Socket编程

1.1 Dial()函数

Go语言提供了简洁的网络连接方式,通过net.Dial()函数可以轻松建立网络连接:

go 复制代码
package main

import (
    "fmt"
    "net"
)

func main() {
    conn, err := net.Dial("tcp", "www.google.com:80")
    if err != nil {
        fmt.Println("连接失败:", err)
        return
    }
    defer conn.Close()
    fmt.Println("连接成功")
}

关键点:

  • 支持多种网络协议:tcp、udp、unix等
  • 自动处理DNS解析
  • 返回连接对象和错误信息

1.2 ICMP示例程序

ICMP(Internet Control Message Protocol)用于网络诊断,类似ping命令:

go 复制代码
package main

import (
    "fmt"
    "net"
    "os"
    "time"
)

func main() {
    conn, err := net.Dial("ip4:icmp", "www.baidu.com")
    if err != nil {
        fmt.Println("ICMP连接失败:", err)
        os.Exit(1)
    }
    defer conn.Close()
    
    // 发送ICMP回显请求
    data := []byte("Hello ICMP")
    _, err = conn.Write(data)
    if err != nil {
        fmt.Println("发送失败:", err)
        return
    }
    
    // 设置读取超时
    conn.SetReadDeadline(time.Now().Add(3 * time.Second))
    
    buffer := make([]byte, 1024)
    n, err := conn.Read(buffer)
    if err != nil {
        fmt.Println("读取失败:", err)
        return
    }
    
    fmt.Printf("收到回复: %s\n", string(buffer[:n]))
}

1.3 TCP示例程序

TCP是最常用的可靠传输协议:

TCP客户端:

go 复制代码
package main

import (
    "fmt"
    "net"
)

func main() {
    // 连接到TCP服务器
    conn, err := net.Dial("tcp", "localhost:8080")
    if err != nil {
        fmt.Println("连接失败:", err)
        return
    }
    defer conn.Close()
    
    // 发送数据
    message := "Hello TCP Server"
    _, err = conn.Write([]byte(message))
    if err != nil {
        fmt.Println("发送失败:", err)
        return
    }
    
    // 读取响应
    buffer := make([]byte, 1024)
    n, err := conn.Read(buffer)
    if err != nil {
        fmt.Println("读取失败:", err)
        return
    }
    
    fmt.Printf("服务器响应: %s\n", string(buffer[:n]))
}

TCP服务端:

go 复制代码
package main

import (
    "fmt"
    "net"
)

func main() {
    // 监听TCP端口
    listener, err := net.Listen("tcp", ":8080")
    if err != nil {
        fmt.Println("监听失败:", err)
        return
    }
    defer listener.Close()
    
    fmt.Println("TCP服务器启动,监听端口8080...")
    
    for {
        // 接受客户端连接
        conn, err := listener.Accept()
        if err != nil {
            fmt.Println("接受连接失败:", err)
            continue
        }
        
        // 处理客户端请求
        go handleClient(conn)
    }
}

func handleClient(conn net.Conn) {
    defer conn.Close()
    
    buffer := make([]byte, 1024)
    n, err := conn.Read(buffer)
    if err != nil {
        fmt.Println("读取失败:", err)
        return
    }
    
    fmt.Printf("收到客户端消息: %s\n", string(buffer[:n]))
    
    // 回复客户端
    response := "消息已收到"
    _, err = conn.Write([]byte(response))
    if err != nil {
        fmt.Println("回复失败:", err)
    }
}

1.4 更丰富的网络通信

包括UDP通信、Unix域套接字等:

go 复制代码
// UDP示例
conn, err := net.Dial("udp", "localhost:8081")
// Unix域套接字示例
conn, err := net.Dial("unix", "/tmp/socket")

2. HTTP编程

2.1 HTTP客户端

Go语言的net/http包提供了强大的HTTP客户端功能:

go 复制代码
package main

import (
    "fmt"
    "io"
    "net/http"
    "strings"
    "time"
)

func main() {
    // GET请求
    resp, err := http.Get("https://api.github.com/users/golang")
    if err != nil {
        fmt.Println("请求失败:", err)
        return
    }
    defer resp.Body.Close()
    
    body, err := io.ReadAll(resp.Body)
    if err != nil {
        fmt.Println("读取响应失败:", err)
        return
    }
    
    fmt.Printf("状态码: %d\n", resp.StatusCode)
    fmt.Printf("响应内容: %s\n", string(body))
}

自定义HTTP客户端:

go 复制代码
client := &http.Client{
    Timeout: time.Second * 30,
}

req, err := http.NewRequest("POST", "https://api.example.com", strings.NewReader("data"))
req.Header.Set("Content-Type", "application/json")
resp, err := client.Do(req)

2.2 HTTP服务端

创建HTTP服务器非常简单:

go 复制代码
package main

import (
    "fmt"
    "net/http"
    "time"
)

func main() {
    // 注册路由处理器
    http.HandleFunc("/", homeHandler)
    http.HandleFunc("/api/users", usersHandler)
    
    fmt.Println("HTTP服务器启动,监听端口8080...")
    err := http.ListenAndServe(":8080", nil)
    if err != nil {
        fmt.Println("服务器启动失败:", err)
    }
}

func homeHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "欢迎访问Go HTTP服务器!")
}

func usersHandler(w http.ResponseWriter, r *http.Request) {
    switch r.Method {
    case "GET":
        fmt.Fprintf(w, "获取用户列表")
    case "POST":
        fmt.Fprintf(w, "创建新用户")
    default:
        http.Error(w, "方法不支持", http.StatusMethodNotAllowed)
    }
}

3. RPC编程

3.1 Go语言中的RPC支持与处理

Go语言内置了RPC(远程过程调用)支持:

RPC服务端:

go 复制代码
package main

import (
    "net"
    "net/rpc"
)

type Calculator struct{}

type Args struct {
    A, B int
}

func (c *Calculator) Add(args *Args, reply *int) error {
    *reply = args.A + args.B
    return nil
}

func (c *Calculator) Multiply(args *Args, reply *int) error {
    *reply = args.A * args.B
    return nil
}

func main() {
    calc := new(Calculator)
    rpc.Register(calc)
    
    listener, err := net.Listen("tcp", ":8081")
    if err != nil {
        panic(err)
    }
    defer listener.Close()
    
    for {
        conn, err := listener.Accept()
        if err != nil {
            continue
        }
        go rpc.ServeConn(conn)
    }
}

RPC客户端:

go 复制代码
package main

import (
    "fmt"
    "net/rpc"
)

type Args struct {
    A, B int
}

func main() {
    client, err := rpc.Dial("tcp", "localhost:8081")
    if err != nil {
        panic(err)
    }
    defer client.Close()
    
    args := &Args{7, 8}
    var reply int
    
    err = client.Call("Calculator.Add", args, &reply)
    if err != nil {
        panic(err)
    }
    
    fmt.Printf("7 + 8 = %d\n", reply)
}

3.2 Gob简介

Gob是Go语言特有的序列化格式,用于RPC通信:

go 复制代码
package main

import (
    "bytes"
    "encoding/gob"
    "fmt"
)

type Person struct {
    Name string
    Age  int
}

func main() {
    // 编码
    var buffer bytes.Buffer
    encoder := gob.NewEncoder(&buffer)
    
    person := Person{Name: "张三", Age: 30}
    err := encoder.Encode(person)
    if err != nil {
        panic(err)
    }
    
    // 解码
    decoder := gob.NewDecoder(&buffer)
    var decodedPerson Person
    err = decoder.Decode(&decodedPerson)
    if err != nil {
        panic(err)
    }
    
    fmt.Printf("解码结果: %+v\n", decodedPerson)
}

3.3 设计优雅的RPC接口

良好的RPC接口设计原则:

go 复制代码
// 定义清晰的服务接口
type UserService interface {
    GetUser(id int) (*User, error)
    CreateUser(user *User) error
    UpdateUser(user *User) error
    DeleteUser(id int) error
}

// 实现服务
type UserServiceImpl struct {
    users map[int]*User
}

func (s *UserServiceImpl) GetUser(id int, user *User) error {
    if u, exists := s.users[id]; exists {
        *user = *u
        return nil
    }
    return fmt.Errorf("用户不存在: %d", id)
}

4. JSON处理

4.1 编码为JSON格式

将Go数据结构转换为JSON:

go 复制代码
package main

import (
    "encoding/json"
    "fmt"
)

type User struct {
    ID       int    `json:"id"`
    Name     string `json:"name"`
    Email    string `json:"email"`
    IsActive bool   `json:"is_active"`
}

func main() {
    user := User{
        ID:       1,
        Name:     "张三",
        Email:    "zhangsan@example.com",
        IsActive: true,
    }
    
    // 编码为JSON
    jsonData, err := json.Marshal(user)
    if err != nil {
        fmt.Println("JSON编码失败:", err)
        return
    }
    
    fmt.Printf("JSON数据: %s\n", string(jsonData))
    
    // 美化输出
    jsonPretty, err := json.MarshalIndent(user, "", "  ")
    if err != nil {
        fmt.Println("美化JSON失败:", err)
        return
    }
    
    fmt.Printf("美化的JSON:\n%s\n", string(jsonPretty))
}

4.2 解码JSON数据

将JSON数据转换为Go数据结构:

go 复制代码
package main

import (
    "encoding/json"
    "fmt"
)

type User struct {
    ID       int    `json:"id"`
    Name     string `json:"name"`
    Email    string `json:"email"`
    IsActive bool   `json:"is_active"`
}

func main() {
    jsonStr := `{"id":1,"name":"李四","email":"lisi@example.com","is_active":true}`
    
    var user User
    err := json.Unmarshal([]byte(jsonStr), &user)
    if err != nil {
        fmt.Println("JSON解码失败:", err)
        return
    }
    
    fmt.Printf("解码结果: %+v\n", user)
}

4.3 解码未知结构的JSON数据

处理动态JSON结构:

go 复制代码
package main

import (
    "encoding/json"
    "fmt"
)

func main() {
    jsonStr := `{
        "name": "王五",
        "age": 25,
        "skills": ["Go", "Python", "JavaScript"],
        "address": {
            "city": "北京",
            "district": "朝阳区"
        }
    }`
    
    var data map[string]interface{}
    err := json.Unmarshal([]byte(jsonStr), &data)
    if err != nil {
        fmt.Println("解码失败:", err)
        return
    }
    
    fmt.Printf("姓名: %s\n", data["name"])
    fmt.Printf("年龄: %.0f\n", data["age"])
    
    // 处理数组
    if skills, ok := data["skills"].([]interface{}); ok {
        fmt.Print("技能: ")
        for _, skill := range skills {
            fmt.Printf("%s ", skill)
        }
        fmt.Println()
    }
    
    // 处理嵌套对象
    if address, ok := data["address"].(map[string]interface{}); ok {
        fmt.Printf("地址: %s %s\n", address["city"], address["district"])
    }
}

4.4 JSON的流式读写

处理大型JSON数据时使用流式处理:

go 复制代码
package main

import (
    "encoding/json"
    "fmt"
    "strings"
)

func main() {
    jsonStream := `
        {"name":"用户1","age":20}
        {"name":"用户2","age":25}
        {"name":"用户3","age":30}
    `
    
    decoder := json.NewDecoder(strings.NewReader(jsonStream))
    
    for decoder.More() {
        var user map[string]interface{}
        err := decoder.Decode(&user)
        if err != nil {
            fmt.Println("解码失败:", err)
            break
        }
        fmt.Printf("用户: %s, 年龄: %.0f\n", user["name"], user["age"])
    }
}

5. 网站开发

5.1 最简单的网站程序

创建一个基础的Web服务器:

go 复制代码
package main

import (
    "fmt"
    "net/http"
    "time"
)

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "<h1>欢迎来到Go Web世界!</h1>")
        fmt.Fprintf(w, "<p>当前时间: %s</p>", time.Now().Format("2006-01-02 15:04:05"))
    })
    
    fmt.Println("Web服务器启动,访问 http://localhost:8080")
    http.ListenAndServe(":8080", nil)
}

5.2 net/http包简介

Go的net/http包功能强大,包含:

核心组件:

  • http.Handler接口:处理HTTP请求的核心接口
  • http.ServeMux:HTTP请求路由器
  • http.Server:HTTP服务器配置

中间件示例:

go 复制代码
package main

import (
    "fmt"
    "net/http"
    "time"
)

func loggingMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        fmt.Printf("请求: %s %s\n", r.Method, r.URL.Path)
        next.ServeHTTP(w, r)
    })
}

func main() {
    mux := http.NewServeMux()
    mux.HandleFunc("/api", apiHandler)
    
    // 应用中间件
    handler := loggingMiddleware(mux)
    
    server := &http.Server{
        Addr:         ":8080",
        Handler:      handler,
        ReadTimeout:  10 * time.Second,
        WriteTimeout: 10 * time.Second,
    }
    
    server.ListenAndServe()
}

func apiHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "API响应")
}

5.3 开发一个简单的相册网站

构建一个完整的相册应用:

go 复制代码
package main

import (
    "html/template"
    "net/http"
    "fmt"
)

type Photo struct {
    ID       int
    Title    string
    Filename string
    Caption  string
}

type Album struct {
    Title  string
    Photos []Photo
}

func main() {
    // 静态文件服务
    http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static/"))))
    
    // 路由
    http.HandleFunc("/", albumHandler)
    http.HandleFunc("/photo/", photoHandler)
    http.HandleFunc("/upload", uploadHandler)
    
    fmt.Println("相册网站启动,访问 http://localhost:8080")
    http.ListenAndServe(":8080", nil)
}

func albumHandler(w http.ResponseWriter, r *http.Request) {
    album := Album{
        Title: "我的相册",
        Photos: []Photo{
            {1, "风景照", "landscape.jpg", "美丽的风景"},
            {2, "人物照", "portrait.jpg", "朋友合影"},
        },
    }
    
    tmpl := `
    <!DOCTYPE html>
    <html>
    <head>
        <title>{{.Title}}</title>
        <style>
            .photo { margin: 10px; display: inline-block; }
            .photo img { width: 200px; height: 150px; object-fit: cover; }
        </style>
    </head>
    <body>
        <h1>{{.Title}}</h1>
        {{range .Photos}}
        <div class="photo">
            <img src="/static/{{.Filename}}" alt="{{.Title}}">
            <p>{{.Caption}}</p>
        </div>
        {{end}}
        <a href="/upload">上传新照片</a>
    </body>
    </html>
    `
    
    t, _ := template.New("album").Parse(tmpl)
    t.Execute(w, album)
}

func photoHandler(w http.ResponseWriter, r *http.Request) {
    // 处理单张照片显示
    fmt.Fprintf(w, "照片详情页面")
}

func uploadHandler(w http.ResponseWriter, r *http.Request) {
    if r.Method == "POST" {
        // 处理文件上传
        file, header, err := r.FormFile("photo")
        if err != nil {
            http.Error(w, "上传失败", http.StatusBadRequest)
            return
        }
        defer file.Close()
        
        fmt.Printf("上传文件: %s\n", header.Filename)
        fmt.Fprintf(w, "文件上传成功: %s", header.Filename)
    } else {
        // 显示上传表单
        uploadForm := `
        <!DOCTYPE html>
        <html>
        <head><title>上传照片</title></head>
        <body>
            <h1>上传新照片</h1>
            <form method="POST" enctype="multipart/form-data">
                <input type="file" name="photo" accept="image/*" required>
                <br><br>
                <input type="submit" value="上传照片">
            </form>
            <a href="/">返回相册</a>
        </body>
        </html>
        `
        fmt.Fprintf(w, uploadForm)
    }
}

学习建议

  1. 循序渐进:从Socket基础开始,逐步掌握HTTP和RPC
  2. 动手实践:每个示例都要亲自运行和修改
  3. 理解原理:不仅要会用,还要理解底层网络原理
  4. 项目实战:尝试构建完整的网络应用项目
  5. 性能优化:学习连接池、超时控制等高级特性

练习题

go 复制代码
package main

import (
	"bufio"
	"bytes"
	"encoding/gob"
	"encoding/json"
	"fmt"
	"html/template"
	"io"
	"log"
	"net"
	"net/http"
	"net/rpc"
	//"os"
	"strconv"
	"strings"
	"time"
)

/*
===========================================
Go语言网络编程练习题集
===========================================

本文件包含了Go语言网络编程的完整练习题和标准答案,涵盖:
1. Socket编程
2. HTTP编程
3. RPC编程
4. JSON处理
5. 网站开发

每个练习都有详细的题目描述、实现代码和运行说明。
*/

// ===========================================
// 第1章:Socket编程练习
// ===========================================

// 练习1.1:使用Dial()函数连接远程服务器
func exercise1_1() {
	fmt.Println("\n=== 练习1.1:Dial()函数连接测试 ===")

	// 题目:使用net.Dial()连接到百度服务器,检查连接状态
	conn, err := net.Dial("tcp", "www.baidu.com:80")
	if err != nil {
		fmt.Printf("连接失败: %v\n", err)
		return
	}
	defer conn.Close()

	fmt.Println("✓ 成功连接到百度服务器")
	fmt.Printf("本地地址: %s\n", conn.LocalAddr())
	fmt.Printf("远程地址: %s\n", conn.RemoteAddr())

	// 发送HTTP请求
	request := "GET / HTTP/1.1\r\nHost: www.baidu.com\r\n\r\n"
	_, err = conn.Write([]byte(request))
	if err != nil {
		fmt.Printf("发送请求失败: %v\n", err)
		return
	}

	// 读取响应头
	buffer := make([]byte, 1024)
	n, err := conn.Read(buffer)
	if err != nil {
		fmt.Printf("读取响应失败: %v\n", err)
		return
	}

	fmt.Printf("收到响应 (%d 字节):\n%s\n", n, string(buffer[:200]))
}

// 练习1.2:ICMP程序实现(需要管理员权限)
func exercise1_2() {
	fmt.Println("\n=== 练习1.2:ICMP程序实现 ===")

	// 题目:实现一个简单的ping程序
	// 注意:ICMP需要root权限,这里演示基本结构

	fmt.Println("ICMP程序结构演示(实际运行需要管理员权限):")
	fmt.Println(`
	conn, err := net.Dial("ip4:icmp", "www.google.com")
	if err != nil {
		log.Fatal("需要管理员权限:", err)
	}
	defer conn.Close()
	
	// 构造ICMP回显请求包
	data := []byte("Hello ICMP")
	_, err = conn.Write(data)
	if err != nil {
		log.Fatal("发送ICMP包失败:", err)
	}
	
	// 设置读取超时
	conn.SetReadDeadline(time.Now().Add(3 * time.Second))
	buffer := make([]byte, 1024)
	n, err := conn.Read(buffer)
	if err != nil {
		log.Fatal("读取ICMP响应失败:", err)
	}
	
	fmt.Printf("收到ICMP回复: %s\n", string(buffer[:n]))
	`)
}

// 练习1.3:TCP客户端服务器实现
type TCPServer struct {
	listener net.Listener
	clients  map[string]net.Conn
}

func exercise1_3() {
	fmt.Println("\n=== 练习1.3:TCP客户端服务器 ===")

	// 题目:实现一个TCP回声服务器和客户端

	// 启动服务器
	go func() {
		server := &TCPServer{
			clients: make(map[string]net.Conn),
		}
		server.start()
	}()

	// 等待服务器启动
	time.Sleep(100 * time.Millisecond)

	// 启动客户端
	tcpClient()
}

func (s *TCPServer) start() {
	var err error
	s.listener, err = net.Listen("tcp", ":8081")
	if err != nil {
		log.Printf("TCP服务器启动失败: %v", err)
		return
	}
	defer s.listener.Close()

	fmt.Println("✓ TCP服务器启动成功,监听端口 8081")

	for {
		conn, err := s.listener.Accept()
		if err != nil {
			log.Printf("接受连接失败: %v", err)
			continue
		}

		go s.handleClient(conn)
	}
}

func (s *TCPServer) handleClient(conn net.Conn) {
	defer conn.Close()
	clientAddr := conn.RemoteAddr().String()
	s.clients[clientAddr] = conn

	fmt.Printf("✓ 客户端连接: %s\n", clientAddr)

	scanner := bufio.NewScanner(conn)
	for scanner.Scan() {
		message := scanner.Text()
		fmt.Printf("收到消息 [%s]: %s\n", clientAddr, message)

		// 回声响应
		response := fmt.Sprintf("回声: %s", message)
		conn.Write([]byte(response + "\n"))

		if message == "quit" {
			break
		}
	}

	delete(s.clients, clientAddr)
	fmt.Printf("✓ 客户端断开: %s\n", clientAddr)
}

func tcpClient() {
	conn, err := net.Dial("tcp", "localhost:8081")
	if err != nil {
		fmt.Printf("连接服务器失败: %v\n", err)
		return
	}
	defer conn.Close()

	fmt.Println("✓ 连接到TCP服务器成功")

	// 发送测试消息
	messages := []string{"Hello", "World", "Go语言", "quit"}

	for _, msg := range messages {
		// 发送消息
		_, err := conn.Write([]byte(msg + "\n"))
		if err != nil {
			fmt.Printf("发送消息失败: %v\n", err)
			break
		}

		// 读取响应
		buffer := make([]byte, 1024)
		n, err := conn.Read(buffer)
		if err != nil {
			fmt.Printf("读取响应失败: %v\n", err)
			break
		}

		fmt.Printf("服务器响应: %s", string(buffer[:n]))
		time.Sleep(500 * time.Millisecond)
	}
}

// 练习1.4:UDP通信实现
func exercise1_4() {
	fmt.Println("\n=== 练习1.4:UDP通信实现 ===")

	// 题目:实现UDP客户端和服务器通信

	// 启动UDP服务器
	go udpServer()
	time.Sleep(100 * time.Millisecond)

	// 启动UDP客户端
	udpClient()
}

func udpServer() {
	addr, err := net.ResolveUDPAddr("udp", ":8082")
	if err != nil {
		log.Printf("解析UDP地址失败: %v", err)
		return
	}

	conn, err := net.ListenUDP("udp", addr)
	if err != nil {
		log.Printf("UDP服务器启动失败: %v", err)
		return
	}
	defer conn.Close()

	fmt.Println("✓ UDP服务器启动成功,监听端口 8082")

	buffer := make([]byte, 1024)
	for i := 0; i < 3; i++ { // 只处理3个消息然后退出
		n, clientAddr, err := conn.ReadFromUDP(buffer)
		if err != nil {
			log.Printf("读取UDP消息失败: %v", err)
			continue
		}

		message := string(buffer[:n])
		fmt.Printf("收到UDP消息 [%s]: %s\n", clientAddr, message)

		// 响应客户端
		response := fmt.Sprintf("UDP回声: %s", message)
		_, err = conn.WriteToUDP([]byte(response), clientAddr)
		if err != nil {
			log.Printf("发送UDP响应失败: %v", err)
		}
	}
}

func udpClient() {
	conn, err := net.Dial("udp", "localhost:8082")
	if err != nil {
		fmt.Printf("连接UDP服务器失败: %v\n", err)
		return
	}
	defer conn.Close()

	fmt.Println("✓ 连接到UDP服务器成功")

	messages := []string{"UDP消息1", "UDP消息2", "UDP消息3"}

	for _, msg := range messages {
		// 发送消息
		_, err := conn.Write([]byte(msg))
		if err != nil {
			fmt.Printf("发送UDP消息失败: %v\n", err)
			continue
		}

		// 读取响应
		buffer := make([]byte, 1024)
		n, err := conn.Read(buffer)
		if err != nil {
			fmt.Printf("读取UDP响应失败: %v\n", err)
			continue
		}

		fmt.Printf("服务器响应: %s\n", string(buffer[:n]))
		time.Sleep(200 * time.Millisecond)
	}
}

// ===========================================
// 第2章:HTTP编程练习
// ===========================================

// 练习2.1:HTTP客户端实现
func exercise2_1() {
	fmt.Println("\n=== 练习2.1:HTTP客户端实现 ===")

	// 题目:实现HTTP GET和POST请求

	// GET请求
	fmt.Println("1. 执行HTTP GET请求:")
	resp, err := http.Get("https://httpbin.org/get?param1=value1")
	if err != nil {
		fmt.Printf("GET请求失败: %v\n", err)
		return
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		fmt.Printf("读取响应失败: %v\n", err)
		return
	}

	fmt.Printf("✓ GET响应状态: %s\n", resp.Status)
	fmt.Printf("响应内容(前200字符): %s...\n", string(body[:min(200, len(body))]))

	// POST请求
	fmt.Println("\n2. 执行HTTP POST请求:")
	postData := strings.NewReader(`{"name":"Go语言","type":"编程语言"}`)
	resp, err = http.Post("https://httpbin.org/post", "application/json", postData)
	if err != nil {
		fmt.Printf("POST请求失败: %v\n", err)
		return
	}
	defer resp.Body.Close()

	body, err = io.ReadAll(resp.Body)
	if err != nil {
		fmt.Printf("读取POST响应失败: %v\n", err)
		return
	}

	fmt.Printf("✓ POST响应状态: %s\n", resp.Status)
	fmt.Printf("响应内容(前200字符): %s...\n", string(body[:min(200, len(body))]))
	
}

// 练习2.2:HTTP服务器实现
func exercise2_2() {
	fmt.Println("\n=== 练习2.2:HTTP服务器实现 ===")

	// 题目:实现一个功能完整的HTTP服务器

	mux := http.NewServeMux()

	// 根路径处理器
	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		html := `
		<!DOCTYPE html>
		<html>
		<head><title>Go HTTP服务器练习</title></head>
		<body>
			<h1>欢迎来到Go HTTP服务器!</h1>
			<ul>
				<li><a href="/api/users">用户API</a></li>
				<li><a href="/api/time">当前时间</a></li>
				<li><a href="/form">表单测试</a></li>
			</ul>
		</body>
		</html>
		`
		w.Header().Set("Content-Type", "text/html; charset=utf-8")
		fmt.Fprint(w, html)
	})

	// API路由
	mux.HandleFunc("/api/users", usersHandler)
	mux.HandleFunc("/api/time", timeHandler)
	mux.HandleFunc("/form", formHandler)

	// 启动服务器
	server := &http.Server{
		Addr:    ":8083",
		Handler: mux,
	}

	go func() {
		fmt.Println("✓ HTTP服务器启动成功,访问 http://localhost:8083")
		if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			log.Printf("HTTP服务器错误: %v", err)
		}
	}()

	// 测试客户端请求
	time.Sleep(100 * time.Millisecond)
	testHTTPServer()
}

func usersHandler(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case "GET":
		users := []map[string]interface{}{
			{"id": 1, "name": "张三", "email": "zhangsan@example.com"},
			{"id": 2, "name": "李四", "email": "lisi@example.com"},
		}
		w.Header().Set("Content-Type", "application/json")
		json.NewEncoder(w).Encode(users)

	case "POST":
		var user map[string]interface{}
		if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
			http.Error(w, "无效的JSON数据", http.StatusBadRequest)
			return
		}
		user["id"] = 3 // 模拟生成ID
		w.Header().Set("Content-Type", "application/json")
		json.NewEncoder(w).Encode(user)

	default:
		http.Error(w, "方法不支持", http.StatusMethodNotAllowed)
	}
}

func timeHandler(w http.ResponseWriter, r *http.Request) {
	response := map[string]string{
		"current_time": time.Now().Format("2006-01-02 15:04:05"),
		"timezone":     "Asia/Shanghai",
	}
	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(response)
}

func formHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method == "GET" {
		html := `
		<!DOCTYPE html>
		<html>
		<head><title>表单测试</title></head>
		<body>
			<h2>表单提交测试</h2>
			<form method="POST">
				<p>姓名: <input type="text" name="name" required></p>
				<p>邮箱: <input type="email" name="email" required></p>
				<p><input type="submit" value="提交"></p>
			</form>
		</body>
		</html>
		`
		w.Header().Set("Content-Type", "text/html; charset=utf-8")
		fmt.Fprint(w, html)
	} else if r.Method == "POST" {
		r.ParseForm()
		name := r.FormValue("name")
		email := r.FormValue("email")

		response := fmt.Sprintf(`
		<!DOCTYPE html>
		<html>
		<head><title>提交结果</title></head>
		<body>
			<h2>表单提交成功!</h2>
			<p>姓名: %s</p>
			<p>邮箱: %s</p>
			<a href="/form">返回表单</a>
		</body>
		</html>
		`, name, email)

		w.Header().Set("Content-Type", "text/html; charset=utf-8")
		fmt.Fprint(w, response)
	}
}

func testHTTPServer() {
	fmt.Println("测试HTTP服务器:")

	// 测试GET请求
	resp, err := http.Get("http://localhost:8083/api/time")
	if err != nil {
		fmt.Printf("测试GET请求失败: %v\n", err)
		return
	}
	defer resp.Body.Close()

	body, _ := io.ReadAll(resp.Body)
	fmt.Printf("✓ GET /api/time 响应: %s\n", string(body))

	// 测试POST请求
	postData := strings.NewReader(`{"name":"新用户","email":"newuser@example.com"}`)
	resp, err = http.Post("http://localhost:8083/api/users", "application/json", postData)
	if err != nil {
		fmt.Printf("测试POST请求失败: %v\n", err)
		return
	}
	defer resp.Body.Close()

	body, _ = io.ReadAll(resp.Body)
	fmt.Printf("✓ POST /api/users 响应: %s\n", string(body))
}

// ===========================================
// 第3章:RPC编程练习
// ===========================================

// 练习3.1:RPC服务实现
type Calculator struct{}

type MathArgs struct {
	A, B float64
}

type MathResult struct {
	Result float64
	Error  string
}

func (c *Calculator) Add(args *MathArgs, result *MathResult) error {
	result.Result = args.A + args.B
	return nil
}

func (c *Calculator) Subtract(args *MathArgs, result *MathResult) error {
	result.Result = args.A - args.B
	return nil
}

func (c *Calculator) Multiply(args *MathArgs, result *MathResult) error {
	result.Result = args.A * args.B
	return nil
}

func (c *Calculator) Divide(args *MathArgs, result *MathResult) error {
	if args.B == 0 {
		result.Error = "除数不能为零"
		return fmt.Errorf("division by zero")
	}
	result.Result = args.A / args.B
	return nil
}

func exercise3_1() {
	fmt.Println("\n=== 练习3.1:RPC服务实现 ===")

	// 题目:实现一个RPC计算服务器

	// 注册RPC服务
	calc := new(Calculator)
	rpc.Register(calc)

	// 启动RPC服务器
	go func() {
		listener, err := net.Listen("tcp", ":8084")
		if err != nil {
			log.Printf("RPC服务器启动失败: %v", err)
			return
		}
		defer listener.Close()

		fmt.Println("✓ RPC服务器启动成功,监听端口 8084")

		for {
			conn, err := listener.Accept()
			if err != nil {
				log.Printf("接受RPC连接失败: %v", err)
				continue
			}
			go rpc.ServeConn(conn)
		}
	}()

	// 等待服务器启动
	time.Sleep(100 * time.Millisecond)

	// 测试RPC客户端
	rpcClient()
}

func rpcClient() {
	client, err := rpc.Dial("tcp", "localhost:8084")
	if err != nil {
		fmt.Printf("连接RPC服务器失败: %v\n", err)
		return
	}
	defer client.Close()

	fmt.Println("✓ 连接到RPC服务器成功")

	// 测试各种数学运算
	tests := []struct {
		method string
		args   MathArgs
	}{
		{"Calculator.Add", MathArgs{10, 5}},
		{"Calculator.Subtract", MathArgs{10, 3}},
		{"Calculator.Multiply", MathArgs{4, 7}},
		{"Calculator.Divide", MathArgs{20, 4}},
		{"Calculator.Divide", MathArgs{10, 0}}, // 测试除零错误
	}

	for _, test := range tests {
		var result MathResult
		err := client.Call(test.method, &test.args, &result)

		if err != nil {
			fmt.Printf("RPC调用失败 [%s]: %v\n", test.method, err)
		} else if result.Error != "" {
			fmt.Printf("运算错误 [%s(%.1f, %.1f)]: %s\n",
				test.method, test.args.A, test.args.B, result.Error)
		} else {
			fmt.Printf("✓ %s(%.1f, %.1f) = %.2f\n",
				test.method, test.args.A, test.args.B, result.Result)
		}
	}
}

// 练习3.2:Gob编码实现
type Person struct {
	Name    string
	Age     int
	Email   string
	Hobbies []string
}

func exercise3_2() {
	fmt.Println("\n=== 练习3.2:Gob编码实现 ===")

	// 题目:使用Gob进行数据序列化和反序列化

	// 原始数据
	person := Person{
		Name:    "张三",
		Age:     28,
		Email:   "zhangsan@example.com",
		Hobbies: []string{"编程", "阅读", "旅行"},
	}

	fmt.Printf("原始数据: %+v\n", person)

	// 编码
	var buffer bytes.Buffer
	encoder := gob.NewEncoder(&buffer)
	err := encoder.Encode(person)
	if err != nil {
		fmt.Printf("Gob编码失败: %v\n", err)
		return
	}

	fmt.Printf("✓ Gob编码成功,数据大小: %d 字节\n", buffer.Len())

	// 解码
	decoder := gob.NewDecoder(&buffer)
	var decodedPerson Person
	err = decoder.Decode(&decodedPerson)
	if err != nil {
		fmt.Printf("Gob解码失败: %v\n", err)
		return
	}

	fmt.Printf("✓ Gob解码成功: %+v\n", decodedPerson)

	// 验证数据一致性
	if person.Name == decodedPerson.Name && person.Age == decodedPerson.Age {
		fmt.Println("✓ 数据一致性验证通过")
	} else {
		fmt.Println("✗ 数据一致性验证失败")
	}
}

// 练习3.3:优雅的RPC接口设计
type UserService struct {
	users map[int]*User
}

type User struct {
	ID    int    `json:"id"`
	Name  string `json:"name"`
	Email string `json:"email"`
}

type UserRequest struct {
	ID   int  `json:"id"`
	User User `json:"user"`
}

type UserResponse struct {
	Success bool   `json:"success"`
	Message string `json:"message"`
	User    *User  `json:"user,omitempty"`
	Users   []User `json:"users,omitempty"`
}

func NewUserService() *UserService {
	return &UserService{
		users: map[int]*User{
			1: {ID: 1, Name: "张三", Email: "zhangsan@example.com"},
			2: {ID: 2, Name: "李四", Email: "lisi@example.com"},
		},
	}
}

func (s *UserService) GetUser(req *UserRequest, resp *UserResponse) error {
	if user, exists := s.users[req.ID]; exists {
		resp.Success = true
		resp.Message = "用户查询成功"
		resp.User = user
	} else {
		resp.Success = false
		resp.Message = fmt.Sprintf("用户不存在: ID=%d", req.ID)
	}
	return nil
}

func (s *UserService) CreateUser(req *UserRequest, resp *UserResponse) error {
	// 生成新ID
	newID := len(s.users) + 1
	req.User.ID = newID

	s.users[newID] = &req.User
	resp.Success = true
	resp.Message = "用户创建成功"
	resp.User = &req.User
	return nil
}

func (s *UserService) ListUsers(req *UserRequest, resp *UserResponse) error {
	var users []User
	for _, user := range s.users {
		users = append(users, *user)
	}

	resp.Success = true
	resp.Message = fmt.Sprintf("查询到 %d 个用户", len(users))
	resp.Users = users
	return nil
}

func exercise3_3() {
	fmt.Println("\n=== 练习3.3:优雅的RPC接口设计 ===")

	// 题目:设计一个用户管理的RPC服务

	// 注册服务
	userService := NewUserService()
	rpc.Register(userService)

	// 启动服务器
	go func() {
		listener, err := net.Listen("tcp", ":8085")
		if err != nil {
			log.Printf("用户服务RPC服务器启动失败: %v", err)
			return
		}
		defer listener.Close()

		fmt.Println("✓ 用户服务RPC服务器启动成功,监听端口 8085")

		for {
			conn, err := listener.Accept()
			if err != nil {
				continue
			}
			go rpc.ServeConn(conn)
		}
	}()

	time.Sleep(100 * time.Millisecond)

	// 测试客户端
	userServiceClient()
}

func userServiceClient() {
	client, err := rpc.Dial("tcp", "localhost:8085")
	if err != nil {
		fmt.Printf("连接用户服务失败: %v\n", err)
		return
	}
	defer client.Close()

	fmt.Println("✓ 连接到用户服务成功")

	// 测试获取用户
	var resp UserResponse
	err = client.Call("UserService.GetUser", &UserRequest{ID: 1}, &resp)
	if err != nil {
		fmt.Printf("获取用户失败: %v\n", err)
	} else {
		fmt.Printf("✓ 获取用户: %+v\n", resp)
	}

	// 测试创建用户
	newUser := User{Name: "王五", Email: "wangwu@example.com"}
	err = client.Call("UserService.CreateUser", &UserRequest{User: newUser}, &resp)
	if err != nil {
		fmt.Printf("创建用户失败: %v\n", err)
	} else {
		fmt.Printf("✓ 创建用户: %+v\n", resp)
	}

	// 测试列出所有用户
	err = client.Call("UserService.ListUsers", &UserRequest{}, &resp)
	if err != nil {
		fmt.Printf("列出用户失败: %v\n", err)
	} else {
		fmt.Printf("✓ 用户列表: %+v\n", resp)
	}
}

// ===========================================
// 第4章:JSON处理练习
// ===========================================

// 练习4.1:JSON编码
type Product struct {
	ID          int      `json:"id"`
	Name        string   `json:"name"`
	Price       float64  `json:"price"`
	Categories  []string `json:"categories"`
	InStock     bool     `json:"in_stock"`
	CreatedTime string   `json:"created_time"`
}

func exercise4_1() {
	fmt.Println("\n=== 练习4.1:JSON编码 ===")

	// 题目:将Go结构体编码为JSON

	product := Product{
		ID:          1001,
		Name:        "Go语言编程指南",
		Price:       89.99,
		Categories:  []string{"编程", "计算机", "Go语言"},
		InStock:     true,
		CreatedTime: time.Now().Format("2006-01-02 15:04:05"),
	}

	// 普通编码
	jsonData, err := json.Marshal(product)
	if err != nil {
		fmt.Printf("JSON编码失败: %v\n", err)
		return
	}

	fmt.Printf("✓ JSON编码结果:\n%s\n", string(jsonData))

	// 美化编码
	jsonPretty, err := json.MarshalIndent(product, "", "  ")
	if err != nil {
		fmt.Printf("JSON美化编码失败: %v\n", err)
		return
	}

	fmt.Printf("\n✓ JSON美化编码结果:\n%s\n", string(jsonPretty))
}

// 练习4.2:JSON解码
func exercise4_2() {
	fmt.Println("\n=== 练习4.2:JSON解码 ===")

	// 题目:将JSON字符串解码为Go结构体

	jsonStr := `{
		"id": 2002,
		"name": "Python深度学习",
		"price": 128.50,
		"categories": ["人工智能", "深度学习", "Python"],
		"in_stock": false,
		"created_time": "2024-01-15 10:30:00"
	}`

	var product Product
	err := json.Unmarshal([]byte(jsonStr), &product)
	if err != nil {
		fmt.Printf("JSON解码失败: %v\n", err)
		return
	}

	fmt.Printf("✓ JSON解码成功:\n")
	fmt.Printf("  ID: %d\n", product.ID)
	fmt.Printf("  名称: %s\n", product.Name)
	fmt.Printf("  价格: %.2f\n", product.Price)
	fmt.Printf("  分类: %v\n", product.Categories)
	fmt.Printf("  库存: %t\n", product.InStock)
	fmt.Printf("  创建时间: %s\n", product.CreatedTime)
}

// 练习4.3:解码未知结构的JSON
func exercise4_3() {
	fmt.Println("\n=== 练习4.3:解码未知结构的JSON ===")

	// 题目:处理动态JSON结构

	jsonStr := `{
		"user": {
			"name": "李明",
			"age": 30,
			"skills": ["Java", "Go", "Docker"],
			"address": {
				"country": "中国",
				"city": "北京",
				"postal_code": "100000"
			}
		},
		"projects": [
			{
				"name": "电商系统",
				"status": "完成",
				"team_size": 5
			},
			{
				"name": "微服务框架",
				"status": "进行中",
				"team_size": 3
			}
		],
		"metadata": {
			"version": "1.0",
			"last_updated": "2024-01-20"
		}
	}`

	var data map[string]interface{}
	err := json.Unmarshal([]byte(jsonStr), &data)
	if err != nil {
		fmt.Printf("JSON解码失败: %v\n", err)
		return
	}

	fmt.Println("✓ 动态JSON解码成功:")

	// 处理用户信息
	if user, ok := data["user"].(map[string]interface{}); ok {
		fmt.Printf("用户姓名: %s\n", user["name"])
		fmt.Printf("用户年龄: %.0f\n", user["age"])

		// 处理技能数组
		if skills, ok := user["skills"].([]interface{}); ok {
			fmt.Print("技能: ")
			for i, skill := range skills {
				if i > 0 {
					fmt.Print(", ")
				}
				fmt.Print(skill)
			}
			fmt.Println()
		}

		// 处理嵌套地址对象
		if address, ok := user["address"].(map[string]interface{}); ok {
			fmt.Printf("地址: %s %s %s\n",
				address["country"], address["city"], address["postal_code"])
		}
	}

	// 处理项目数组
	if projects, ok := data["projects"].([]interface{}); ok {
		fmt.Printf("项目数量: %d\n", len(projects))
		for i, proj := range projects {
			if project, ok := proj.(map[string]interface{}); ok {
				fmt.Printf("  项目%d: %s (状态: %s, 团队: %.0f人)\n",
					i+1, project["name"], project["status"], project["team_size"])
			}
		}
	}

	// 处理元数据
	if metadata, ok := data["metadata"].(map[string]interface{}); ok {
		fmt.Printf("版本: %s, 更新时间: %s\n",
			metadata["version"], metadata["last_updated"])
	}
}

// 练习4.4:JSON流式读写
func exercise4_4() {
	fmt.Println("\n=== 练习4.4:JSON流式读写 ===")

	// 题目:处理大量JSON数据的流式读写

	// 模拟大量JSON数据
	jsonStream := `
	{"id":1,"name":"用户A","score":95.5}
	{"id":2,"name":"用户B","score":87.2}
	{"id":3,"name":"用户C","score":92.8}
	{"id":4,"name":"用户D","score":88.1}
	{"id":5,"name":"用户E","score":94.3}
	`

	fmt.Println("✓ 流式解码JSON数据:")

	decoder := json.NewDecoder(strings.NewReader(jsonStream))

	var totalScore float64
	var userCount int

	for decoder.More() {
		var user map[string]interface{}
		err := decoder.Decode(&user)
		if err != nil {
			fmt.Printf("解码失败: %v\n", err)
			continue
		}

		if score, ok := user["score"].(float64); ok {
			totalScore += score
			userCount++
		}

		fmt.Printf("  用户: %s, 分数: %.1f\n", user["name"], user["score"])
	}

	if userCount > 0 {
		avgScore := totalScore / float64(userCount)
		fmt.Printf("✓ 统计结果: %d个用户, 平均分数: %.2f\n", userCount, avgScore)
	}

	// 流式编码示例
	fmt.Println("\n✓ 流式编码JSON数据:")

	var buffer bytes.Buffer
	encoder := json.NewEncoder(&buffer)

	users := []map[string]interface{}{
		{"id": 6, "name": "新用户F", "score": 89.7},
		{"id": 7, "name": "新用户G", "score": 93.1},
		{"id": 8, "name": "新用户H", "score": 91.4},
	}

	for _, user := range users {
		err := encoder.Encode(user)
		if err != nil {
			fmt.Printf("编码失败: %v\n", err)
			continue
		}
	}

	fmt.Printf("编码结果:\n%s", buffer.String())
}

// ===========================================
// 第5章:网站开发练习
// ===========================================

// 练习5.1:最简单的网站程序
func exercise5_1() {
	fmt.Println("\n=== 练习5.1:最简单的网站程序 ===")

	// 题目:创建一个基本的Web服务器

	mux := http.NewServeMux()

	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		html := fmt.Sprintf(`
		<!DOCTYPE html>
		<html>
		<head>
			<title>Go Web练习</title>
			<style>
				body { font-family: Arial, sans-serif; margin: 40px; }
				.info { background: #f0f8ff; padding: 20px; border-radius: 5px; }
			</style>
		</head>
		<body>
			<h1>🚀 欢迎来到Go Web世界!</h1>
			<div class="info">
				<p><strong>当前时间:</strong> %s</p>
				<p><strong>请求方法:</strong> %s</p>
				<p><strong>请求路径:</strong> %s</p>
				<p><strong>用户代理:</strong> %s</p>
			</div>
			<h2>导航</h2>
			<ul>
				<li><a href="/hello">问候页面</a></li>
				<li><a href="/info">服务器信息</a></li>
				<li><a href="/api/status">API状态</a></li>
			</ul>
		</body>
		</html>
		`,
			time.Now().Format("2006-01-02 15:04:05"),
			r.Method,
			r.URL.Path,
			r.UserAgent())

		w.Header().Set("Content-Type", "text/html; charset=utf-8")
		fmt.Fprint(w, html)
	})

	mux.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
		name := r.URL.Query().Get("name")
		if name == "" {
			name = "访客"
		}

		html := fmt.Sprintf(`
		<!DOCTYPE html>
		<html>
		<head><title>问候页面</title></head>
		<body>
			<h1>你好, %s! 👋</h1>
			<p>欢迎使用Go语言Web服务器!</p>
			<a href="/">返回首页</a>
		</body>
		</html>
		`, name)

		w.Header().Set("Content-Type", "text/html; charset=utf-8")
		fmt.Fprint(w, html)
	})

	mux.HandleFunc("/info", func(w http.ResponseWriter, r *http.Request) {
		info := map[string]interface{}{
			"server":    "Go HTTP Server",
			"version":   "1.0",
			"timestamp": time.Now().Unix(),
			"uptime":    "运行中",
		}

		w.Header().Set("Content-Type", "application/json")
		json.NewEncoder(w).Encode(info)
	})

	mux.HandleFunc("/api/status", func(w http.ResponseWriter, r *http.Request) {
		status := map[string]interface{}{
			"status":  "healthy",
			"message": "服务器运行正常",
			"time":    time.Now().Format(time.RFC3339),
		}

		w.Header().Set("Content-Type", "application/json")
		json.NewEncoder(w).Encode(status)
	})

	server := &http.Server{
		Addr:    ":8086",
		Handler: mux,
	}

	go func() {
		fmt.Println("✓ 简单Web服务器启动成功,访问 http://localhost:8086")
		if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			log.Printf("Web服务器错误: %v", err)
		}
	}()

	// 测试请求
	time.Sleep(100 * time.Millisecond)
	testSimpleWebServer()
}

func testSimpleWebServer() {
	fmt.Println("测试简单Web服务器:")

	// 测试首页
	resp, err := http.Get("http://localhost:8086/")
	if err != nil {
		fmt.Printf("测试首页失败: %v\n", err)
		return
	}
	resp.Body.Close()
	fmt.Printf("✓ 首页响应状态: %s\n", resp.Status)

	// 测试API
	resp, err = http.Get("http://localhost:8086/api/status")
	if err != nil {
		fmt.Printf("测试API失败: %v\n", err)
		return
	}
	defer resp.Body.Close()

	var status map[string]interface{}
	json.NewDecoder(resp.Body).Decode(&status)
	fmt.Printf("✓ API状态: %s\n", status["status"])
}

// 练习5.2:net/http包深入使用
func exercise5_2() {
	fmt.Println("\n=== 练习5.2:net/http包深入使用 ===")

	// 题目:实现中间件、路由和高级HTTP功能

	mux := http.NewServeMux()

	// 静态文件服务器(模拟)
	mux.HandleFunc("/static/", func(w http.ResponseWriter, r *http.Request) {
		filename := strings.TrimPrefix(r.URL.Path, "/static/")
		content := fmt.Sprintf("这是静态文件: %s", filename)
		w.Header().Set("Content-Type", "text/plain")
		fmt.Fprint(w, content)
	})

	// RESTful API
	mux.HandleFunc("/api/books", booksHandler)
	mux.HandleFunc("/api/books/", bookHandler)

	// 应用中间件
	handler := loggingMiddleware(corsMiddleware(mux))

	server := &http.Server{
		Addr:         ":8087",
		Handler:      handler,
		ReadTimeout:  10 * time.Second,
		WriteTimeout: 10 * time.Second,
	}

	go func() {
		fmt.Println("✓ 高级HTTP服务器启动成功,访问 http://localhost:8087")
		if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			log.Printf("高级HTTP服务器错误: %v", err)
		}
	}()

	time.Sleep(100 * time.Millisecond)
	testAdvancedWebServer()
}

// 中间件:日志记录
func loggingMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		start := time.Now()
		next.ServeHTTP(w, r)
		fmt.Printf("📝 %s %s - %v\n", r.Method, r.URL.Path, time.Since(start))
	})
}

// 中间件:CORS支持
func corsMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Access-Control-Allow-Origin", "*")
		w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
		w.Header().Set("Access-Control-Allow-Headers", "Content-Type")

		if r.Method == "OPTIONS" {
			w.WriteHeader(http.StatusOK)
			return
		}

		next.ServeHTTP(w, r)
	})
}

type Book struct {
	ID     int     `json:"id"`
	Title  string  `json:"title"`
	Author string  `json:"author"`
	Price  float64 `json:"price"`
}

var books = []Book{
	{1, "Go语言编程", "张三", 89.99},
	{2, "微服务架构", "李四", 128.00},
	{3, "云原生应用", "王五", 156.50},
}

func booksHandler(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case "GET":
		w.Header().Set("Content-Type", "application/json")
		json.NewEncoder(w).Encode(books)

	case "POST":
		var book Book
		if err := json.NewDecoder(r.Body).Decode(&book); err != nil {
			http.Error(w, "无效的JSON数据", http.StatusBadRequest)
			return
		}

		book.ID = len(books) + 1
		books = append(books, book)

		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusCreated)
		json.NewEncoder(w).Encode(book)

	default:
		http.Error(w, "方法不支持", http.StatusMethodNotAllowed)
	}
}

func bookHandler(w http.ResponseWriter, r *http.Request) {
	// 从URL中提取ID
	path := strings.TrimPrefix(r.URL.Path, "/api/books/")
	id, err := strconv.Atoi(path)
	if err != nil {
		http.Error(w, "无效的书籍ID", http.StatusBadRequest)
		return
	}

	// 查找书籍
	var book *Book
	for i := range books {
		if books[i].ID == id {
			book = &books[i]
			break
		}
	}

	if book == nil {
		http.Error(w, "书籍不存在", http.StatusNotFound)
		return
	}

	switch r.Method {
	case "GET":
		w.Header().Set("Content-Type", "application/json")
		json.NewEncoder(w).Encode(book)

	case "PUT":
		var updatedBook Book
		if err := json.NewDecoder(r.Body).Decode(&updatedBook); err != nil {
			http.Error(w, "无效的JSON数据", http.StatusBadRequest)
			return
		}

		updatedBook.ID = id
		*book = updatedBook

		w.Header().Set("Content-Type", "application/json")
		json.NewEncoder(w).Encode(book)

	case "DELETE":
		// 删除书籍
		for i := range books {
			if books[i].ID == id {
				books = append(books[:i], books[i+1:]...)
				break
			}
		}

		w.WriteHeader(http.StatusNoContent)

	default:
		http.Error(w, "方法不支持", http.StatusMethodNotAllowed)
	}
}

func testAdvancedWebServer() {
	fmt.Println("测试高级Web服务器:")

	// 测试GET所有书籍
	resp, err := http.Get("http://localhost:8087/api/books")
	if err != nil {
		fmt.Printf("测试GET书籍列表失败: %v\n", err)
		return
	}
	defer resp.Body.Close()

	var booksList []Book
	json.NewDecoder(resp.Body).Decode(&booksList)
	fmt.Printf("✓ 获取到 %d 本书籍\n", len(booksList))

	// 测试GET单本书籍
	resp, err = http.Get("http://localhost:8087/api/books/1")
	if err != nil {
		fmt.Printf("测试GET单本书籍失败: %v\n", err)
		return
	}
	defer resp.Body.Close()

	var book Book
	json.NewDecoder(resp.Body).Decode(&book)
	fmt.Printf("✓ 获取书籍: %s\n", book.Title)
}

// 练习5.3:简单相册网站
type PhotoAlbum struct {
	Title  string  `json:"title"`
	Photos []Photo `json:"photos"`
}

type Photo struct {
	ID         int    `json:"id"`
	Title      string `json:"title"`
	Filename   string `json:"filename"`
	Caption    string `json:"caption"`
	UploadTime string `json:"upload_time"`
}

var album = PhotoAlbum{
	Title: "我的相册",
	Photos: []Photo{
		{1, "风景照1", "landscape1.jpg", "美丽的山景", "2024-01-15 10:00:00"},
		{2, "人物照1", "portrait1.jpg", "朋友聚会", "2024-01-16 14:30:00"},
		{3, "风景照2", "landscape2.jpg", "海边日落", "2024-01-17 18:45:00"},
	},
}

func exercise5_3() {
	fmt.Println("\n=== 练习5.3:简单相册网站 ===")

	// 题目:开发一个完整的相册网站

	mux := http.NewServeMux()

	// 首页 - 相册展示
	mux.HandleFunc("/", albumPageHandler)

	// 照片详情页
	mux.HandleFunc("/photo/", photoDetailHandler)

	// 上传页面
	mux.HandleFunc("/upload", uploadPageHandler)

	// API接口
	mux.HandleFunc("/api/photos", photosAPIHandler)
	mux.HandleFunc("/api/upload", uploadAPIHandler)

	// 静态文件(模拟)
	mux.HandleFunc("/images/", imageHandler)

	server := &http.Server{
		Addr:    ":8088",
		Handler: mux,
	}

	go func() {
		fmt.Println("✓ 相册网站启动成功,访问 http://localhost:8088")
		if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			log.Printf("相册网站错误: %v", err)
		}
	}()

	time.Sleep(100 * time.Millisecond)
	testAlbumWebsite()
}

func albumPageHandler(w http.ResponseWriter, r *http.Request) {
	tmpl := `
	<!DOCTYPE html>
	<html>
	<head>
		<title>{{.Title}}</title>
		<style>
			body { font-family: Arial, sans-serif; margin: 20px; background: #f5f5f5; }
			.header { text-align: center; margin-bottom: 30px; }
			.photo-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 20px; }
			.photo-card { 
				background: white; 
				border-radius: 8px; 
				padding: 15px; 
				box-shadow: 0 2px 5px rgba(0,0,0,0.1);
				transition: transform 0.2s;
			}
			.photo-card:hover { transform: translateY(-2px); }
			.photo-img { 
				width: 100%; 
				height: 200px; 
				background: #ddd; 
				border-radius: 5px;
				display: flex;
				align-items: center;
				justify-content: center;
				color: #666;
				margin-bottom: 10px;
			}
			.photo-title { font-weight: bold; margin-bottom: 5px; }
			.photo-caption { color: #666; font-size: 14px; margin-bottom: 5px; }
			.photo-time { color: #999; font-size: 12px; }
			.upload-btn { 
				background: #007bff; 
				color: white; 
				padding: 10px 20px; 
				text-decoration: none; 
				border-radius: 5px;
				display: inline-block;
				margin: 20px 0;
			}
		</style>
	</head>
	<body>
		<div class="header">
			<h1>📸 {{.Title}}</h1>
			<a href="/upload" class="upload-btn">上传新照片</a>
		</div>
		<div class="photo-grid">
			{{range .Photos}}
			<div class="photo-card">
				<div class="photo-img">🖼️ {{.Filename}}</div>
				<div class="photo-title">{{.Title}}</div>
				<div class="photo-caption">{{.Caption}}</div>
				<div class="photo-time">{{.UploadTime}}</div>
				<a href="/photo/{{.ID}}">查看详情</a>
			</div>
			{{end}}
		</div>
	</body>
	</html>
	`

	t, err := template.New("album").Parse(tmpl)
	if err != nil {
		http.Error(w, "模板解析错误", http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	t.Execute(w, album)
}

func photoDetailHandler(w http.ResponseWriter, r *http.Request) {
	// 从URL中提取照片ID
	path := strings.TrimPrefix(r.URL.Path, "/photo/")
	id, err := strconv.Atoi(path)
	if err != nil {
		http.Error(w, "无效的照片ID", http.StatusBadRequest)
		return
	}

	// 查找照片
	var photo *Photo
	for i := range album.Photos {
		if album.Photos[i].ID == id {
			photo = &album.Photos[i]
			break
		}
	}

	if photo == nil {
		http.Error(w, "照片不存在", http.StatusNotFound)
		return
	}

	tmpl := `
	<!DOCTYPE html>
	<html>
	<head>
		<title>{{.Title}} - 照片详情</title>
		<style>
			body { font-family: Arial, sans-serif; margin: 20px; }
			.photo-detail { max-width: 600px; margin: 0 auto; text-align: center; }
			.photo-large { 
				width: 100%; 
				height: 400px; 
				background: #ddd; 
				border-radius: 8px;
				display: flex;
				align-items: center;
				justify-content: center;
				color: #666;
				font-size: 24px;
				margin-bottom: 20px;
			}
			.photo-info { text-align: left; background: #f9f9f9; padding: 20px; border-radius: 8px; }
			.back-btn { 
				background: #6c757d; 
				color: white; 
				padding: 8px 16px; 
				text-decoration: none; 
				border-radius: 4px;
				display: inline-block;
				margin-top: 20px;
			}
		</style>
	</head>
	<body>
		<div class="photo-detail">
			<h1>{{.Title}}</h1>
			<div class="photo-large">🖼️ {{.Filename}}</div>
			<div class="photo-info">
				<p><strong>标题:</strong> {{.Title}}</p>
				<p><strong>描述:</strong> {{.Caption}}</p>
				<p><strong>文件名:</strong> {{.Filename}}</p>
				<p><strong>上传时间:</strong> {{.UploadTime}}</p>
			</div>
			<a href="/" class="back-btn">返回相册</a>
		</div>
	</body>
	</html>
	`

	t, err := template.New("photo").Parse(tmpl)
	if err != nil {
		http.Error(w, "模板解析错误", http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	t.Execute(w, photo)
}

func uploadPageHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method == "POST" {
		// 处理表单提交
		title := r.FormValue("title")
		caption := r.FormValue("caption")

		if title == "" {
			http.Error(w, "照片标题不能为空", http.StatusBadRequest)
			return
		}

		// 创建新照片
		newPhoto := Photo{
			ID:         len(album.Photos) + 1,
			Title:      title,
			Filename:   fmt.Sprintf("photo_%d.jpg", len(album.Photos)+1),
			Caption:    caption,
			UploadTime: time.Now().Format("2006-01-02 15:04:05"),
		}

		album.Photos = append(album.Photos, newPhoto)

		// 重定向到首页
		http.Redirect(w, r, "/", http.StatusSeeOther)
		return
	}

	// 显示上传表单
	uploadForm := `
	<!DOCTYPE html>
	<html>
	<head>
		<title>上传照片</title>
		<style>
			body { font-family: Arial, sans-serif; margin: 20px; }
			.upload-form { max-width: 500px; margin: 0 auto; }
			.form-group { margin-bottom: 15px; }
			label { display: block; margin-bottom: 5px; font-weight: bold; }
			input, textarea { 
				width: 100%; 
				padding: 8px; 
				border: 1px solid #ddd; 
				border-radius: 4px;
				box-sizing: border-box;
			}
			textarea { height: 80px; resize: vertical; }
			.submit-btn { 
				background: #28a745; 
				color: white; 
				padding: 10px 20px; 
				border: none;
				border-radius: 4px;
				cursor: pointer;
			}
			.back-btn { 
				background: #6c757d; 
				color: white; 
				padding: 8px 16px; 
				text-decoration: none; 
				border-radius: 4px;
				display: inline-block;
				margin-top: 10px;
			}
		</style>
	</head>
	<body>
		<div class="upload-form">
			<h1>📤 上传新照片</h1>
			<form method="POST">
				<div class="form-group">
					<label for="title">照片标题:</label>
					<input type="text" id="title" name="title" required>
				</div>
				<div class="form-group">
					<label for="caption">照片描述:</label>
					<textarea id="caption" name="caption" placeholder="请输入照片描述..."></textarea>
				</div>
				<div class="form-group">
					<input type="submit" value="上传照片" class="submit-btn">
				</div>
			</form>
			<a href="/" class="back-btn">返回相册</a>
		</div>
	</body>
	</html>
	`

	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	fmt.Fprint(w, uploadForm)
}

func photosAPIHandler(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case "GET":
		w.Header().Set("Content-Type", "application/json")
		json.NewEncoder(w).Encode(album)

	default:
		http.Error(w, "方法不支持", http.StatusMethodNotAllowed)
	}
}

func uploadAPIHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "方法不支持", http.StatusMethodNotAllowed)
		return
	}

	var photo Photo
	if err := json.NewDecoder(r.Body).Decode(&photo); err != nil {
		http.Error(w, "无效的JSON数据", http.StatusBadRequest)
		return
	}

	photo.ID = len(album.Photos) + 1
	photo.UploadTime = time.Now().Format("2006-01-02 15:04:05")
	album.Photos = append(album.Photos, photo)

	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusCreated)
	json.NewEncoder(w).Encode(photo)
}

func imageHandler(w http.ResponseWriter, r *http.Request) {
	// 模拟图片服务
	filename := strings.TrimPrefix(r.URL.Path, "/images/")
	w.Header().Set("Content-Type", "text/plain")
	fmt.Fprintf(w, "这里应该是图片文件: %s", filename)
}

func testAlbumWebsite() {
	fmt.Println("测试相册网站:")

	// 测试获取相册
	resp, err := http.Get("http://localhost:8088/api/photos")
	if err != nil {
		fmt.Printf("测试相册API失败: %v\n", err)
		return
	}
	defer resp.Body.Close()

	var albumData PhotoAlbum
	json.NewDecoder(resp.Body).Decode(&albumData)
	fmt.Printf("✓ 相册包含 %d 张照片\n", len(albumData.Photos))

	// 测试照片详情
	resp, err = http.Get("http://localhost:8088/photo/1")
	if err != nil {
		fmt.Printf("测试照片详情失败: %v\n", err)
		return
	}
	resp.Body.Close()
	fmt.Printf("✓ 照片详情页响应状态: %s\n", resp.Status)
}

// ===========================================
// 工具函数
// ===========================================

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

// ===========================================
// 主函数 - 执行所有练习
// ===========================================

func main() {
	fmt.Println("🎯 Go语言网络编程练习题集")
	fmt.Println("=========================================")

	// 第1章:Socket编程练习
	fmt.Println("\n📡 第1章:Socket编程练习")
	exercise1_1()
	exercise1_2()
	exercise1_3()
	exercise1_4()

	// 第2章:HTTP编程练习
	fmt.Println("\n🌐 第2章:HTTP编程练习")
	exercise2_1()
	exercise2_2()

	// 第3章:RPC编程练习
	fmt.Println("\n🔗 第3章:RPC编程练习")
	exercise3_1()
	exercise3_2()
	exercise3_3()

	// 第4章:JSON处理练习
	fmt.Println("\n📋 第4章:JSON处理练习")
	exercise4_1()
	exercise4_2()
	exercise4_3()
	exercise4_4()

	// 第5章:网站开发练习
	fmt.Println("\n🌍 第5章:网站开发练习")
	exercise5_1()
	exercise5_2()
	exercise5_3()

	fmt.Println("\n🎉 所有练习执行完成!")
	fmt.Println("=========================================")
	fmt.Println("📝 练习总结:")
	fmt.Println("1. Socket编程: 掌握了TCP/UDP通信和网络连接")
	fmt.Println("2. HTTP编程: 学会了HTTP客户端和服务端开发")
	fmt.Println("3. RPC编程: 理解了远程过程调用和Gob序列化")
	fmt.Println("4. JSON处理: 熟练掌握JSON编解码和流式处理")
	fmt.Println("5. 网站开发: 能够开发完整的Web应用程序")
	fmt.Println("\n💡 建议:")
	fmt.Println("- 每个练习都要亲自运行和修改代码")
	fmt.Println("- 尝试扩展功能,如添加错误处理、日志记录等")
	fmt.Println("- 结合实际项目需求,应用所学知识")
	fmt.Println("- 关注性能优化和安全性问题")

	// 保持程序运行一段时间以便测试Web服务器
	fmt.Println("\n⏰ Web服务器将继续运行30秒供您测试...")
	time.Sleep(30 * time.Second)
	fmt.Println("✅ 练习程序结束")
}

/*
===========================================
运行说明
===========================================

1. 编译运行:
   go run network_programming_exercises.go

2. 测试Web服务器:
   - 简单Web服务器: http://localhost:8086
   - HTTP服务器: http://localhost:8083
   - 高级HTTP服务器: http://localhost:8087
   - 相册网站: http://localhost:8088

3. 注意事项:
   - 确保端口8081-8088没有被占用
   - ICMP功能需要管理员权限
   - 某些防火墙可能阻止网络连接

4. 扩展练习:
   - 添加数据库支持
   - 实现用户认证
   - 添加文件上传功能
   - 实现WebSocket通信
   - 添加缓存机制

===========================================
*/
相关推荐
我的征途是星辰大海。6 小时前
java-设计模式-5-创建型模式-建造
java·设计模式
lypzcgf6 小时前
Coze源码分析-API授权-获取令牌列表-后端源码
数据库·人工智能·后端·系统架构·go·开源软件·安全架构
她似晚风般温柔7896 小时前
SpringBoot3 + Netty + Vue3 实现消息推送(最新)
java·websocket·spring·vue·netty
火山kim6 小时前
一文速通liunx命令
java·linux·运维·服务器
冷冷的菜哥6 小时前
ASP.NET Core上传文件到minio
后端·asp.net·上传·asp.net core·minio
渣哥6 小时前
你真的知道 Java 里的 Exception 和 Error 有啥不同吗?
java
几颗流星6 小时前
Spring Boot 项目中使用 Protobuf 序列化
spring boot·后端·性能优化