您现在的位置是:首页 >技术交流 >go服务器网站首页技术交流

go服务器

NurDroid 2025-02-16 12:01:04
简介go服务器

实现一个复杂的服务器需要考虑多个方面,包括网络通信、并发处理、安全性、持久化存储、服务监控等。以下是一个用 Go 语言实现的复杂服务器的示例代码,包含详细的注释说明。这个服务器支持 HTTP 和 WebSocket 通信,具备用户认证、日志记录、并发处理和简单的数据存储功能。
Go 代码示例

package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"sync"
	"time"

	"github.com/gorilla/mux"
	"github.com/gorilla/websocket"
)

// User 数据结构,用于存储用户信息
type User struct {
	Username string `json:"username"`
	Password string `json:"password"`
}

// Message 数据结构,用于 WebSocket 消息传递
type Message struct {
	From    string `json:"from"`
	Content string `json:"content"`
}

// ServerState 用于存储服务器状态信息
type ServerState struct {
	Users    map[string]User
	Online   map[*websocket.Conn]string
	mu       sync.RWMutex
	Message  chan Message
}

// NewServerState 创建一个新的服务器状态
func NewServerState() *ServerState {
	return &ServerState{
		Users:    make(map[string]User),
		Online:   make(map[*websocket.Conn]string),
		Message:  make(chan Message, 10),
	}
}

// RegisterUser 注册用户
func (s *ServerState) RegisterUser(username, password string) bool {
	s.mu.Lock()
	defer s.mu.Unlock()
	if _, exists := s.Users[username]; exists {
		return false
	}
	s.Users[username] = User{Username: username, Password: password}
	return true
}

// AuthenticateUser 用户认证
func (s *ServerState) AuthenticateUser(username, password string) bool {
	s.mu.RLock()
	defer s.mu.RUnlock()
	user, exists := s.Users[username]
	return exists && user.Password == password
}

// BroadcastMessage 广播消息给所有在线用户
func (s *ServerState) BroadcastMessage(msg Message) {
	s.mu.RLock()
	defer s.mu.RUnlock()
	for conn := range s.Online {
		err := conn.WriteJSON(msg)
		if err != nil {
			log.Printf("Error sending message to %s: %v", s.Online[conn], err)
			conn.Close()
			delete(s.Online, conn)
		}
	}
}

// WebSocketHandler WebSocket 连接处理器
func (s *ServerState) WebSocketHandler(w http.ResponseWriter, r *http.Request) {
	conn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println(err)
		return
	}
	defer conn.Close()

	// 用户登录
	var loginData struct {
		Username string `json:"username"`
		Password string `json:"password"`
	}
	if err := conn.ReadJSON(&loginData); err != nil {
		log.Println("Error reading login data:", err)
		return
	}
	if !s.AuthenticateUser(loginData.Username, loginData.Password) {
		log.Println("Authentication failed")
		return
	}

	// 将用户添加到在线列表
	s.mu.Lock()
	s.Online[conn] = loginData.Username
	s.mu.Unlock()

	// 广播用户上线消息
	s.BroadcastMessage(Message{From: loginData.Username, Content: "has joined the chat"})

	// 处理接收到的消息
	for {
		var msg Message
		if err := conn.ReadJSON(&msg); err != nil {
			log.Printf("Error reading message from %s: %v", loginData.Username, err)
			break
		}
		msg.From = loginData.Username
		s.BroadcastMessage(msg)
	}

	// 用户下线
	s.mu.Lock()
	delete(s.Online, conn)
	s.mu.Unlock()
	s.BroadcastMessage(Message{From: loginData.Username, Content: "has left the chat"})
}

// HTTPHandler HTTP 请求处理器
func (s *ServerState) HTTPHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	switch r.Method {
	case http.MethodGet:
		// 返回在线用户列表
		s.mu.RLock()
		onlineUsers := make([]string, 0, len(s.Online))
		for _, username := range s.Online {
			onlineUsers = append(onlineUsers, username)
		}
		s.mu.RUnlock()
		json.NewEncoder(w).Encode(onlineUsers)
	case http.MethodPost:
		// 注册用户
		var user User
		if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
			http.Error(w, "Invalid request", http.StatusBadRequest)
			return
		}
		if s.RegisterUser(user.Username, user.Password) {
			w.WriteHeader(http.StatusCreated)
		} else {
			http.Error(w, "User already exists", http.StatusConflict)
		}
	default:
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
	}
}

// MessageHandler 消息处理协程
func (s *ServerState) MessageHandler() {
	for msg := range s.Message {
		s.BroadcastMessage(msg)
	}
}

var upgrader = websocket.Upgrader{
	CheckOrigin: func(r *http.Request) bool {
		return true
	},
}

func main() {
	// 创建服务器状态
	serverState := NewServerState()

	// 注册 HTTP 和 WebSocket 路由
	r := mux.NewRouter()
	r.HandleFunc("/ws", serverState.WebSocketHandler).Methods(http.MethodGet)
	r.HandleFunc("/users", serverState.HTTPHandler).Methods(http.MethodGet, http.MethodPost)

	// 启动消息处理协程
	go serverState.MessageHandler()

	// 启动 HTTP 服务器
	log.Println("Starting server on :8080")
	if err := http.ListenAndServe(":8080", r); err != nil {
		log.Fatalf("Failed to start server: %v", err)
	}
}

代码说明
用户管理:
支持用户注册和登录,用户信息存储在内存中。
使用简单的用户名和密码进行认证。
WebSocket 通信:
支持 WebSocket 连接,用户可以通过 WebSocket 发送和接收消息。
广播消息给所有在线用户。
HTTP 接口:
提供 HTTP 接口用于注册用户和获取在线用户列表。
并发处理:
使用 sync.RWMutex 保护共享数据,确保线程安全。
使用通道和协程处理消息广播。
日志记录:
使用 log 包记录服务器运行日志。
这个服务器是一个较为复杂的示例,涵盖了基本的网络通信、用户认证和并发处理功能。你可以根据实际需求进一步扩展,例如添加数据库支持、更复杂的用户权限管理等。

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。