做网站需要哪些东西,如何建设运输网站,桂林什么公司做网站推广好,做网站商城要注册什么公司文章目录 8.1 HTTP 客户端与服务端编程 - Go 语言的网络灯塔与探航船8.1.1 基础知识讲解服务端编程客户端编程 8.1.2 重点案例#xff1a;简易博客服务服务端实现客户端实现运行示例 8.1.3 拓展案例 1#xff1a;增加文章评论功能功能描述服务端实现客户端实现 8.1.4 拓展案例… 文章目录 8.1 HTTP 客户端与服务端编程 - Go 语言的网络灯塔与探航船8.1.1 基础知识讲解服务端编程客户端编程 8.1.2 重点案例简易博客服务服务端实现客户端实现运行示例 8.1.3 拓展案例 1增加文章评论功能功能描述服务端实现客户端实现 8.1.4 拓展案例 2实现文章的搜索功能功能描述服务端实现客户端示例 8.2 使用 Goroutines 处理并发请求 - Go 语言的并发船队8.2.1 基础知识讲解8.2.2 重点案例并发下载服务服务端实现测试服务 8.2.3 拓展案例 1并发图片处理服务功能描述服务端实现测试服务 8.2.4 拓展案例 2实时股票行情服务功能描述服务端实现 测试服务 8.3 WebSocket 与 RPC - Go 语言的深海通信线8.3.1 基础知识讲解WebSocketRPC 8.3.2 重点案例实时聊天应用服务端实现客户端实现运行示例 8.3.3 拓展案例 1股票行情实时更新服务服务端实现客户端示例运行示例 8.3.4 拓展案例 2远程系统监控功能描述服务端实现客户端实现运行示例 8.1 HTTP 客户端与服务端编程 - Go 语言的网络灯塔与探航船
8.1.1 基础知识讲解
在Go语言的广阔海域中HTTP客户端与服务端编程是连接世界的桥梁。Go通过其标准库提供了强大而灵活的工具使得构建HTTP服务和发起HTTP请求变得简单直接。
服务端编程
Go的http包提供了构建HTTP服务的必要工具。通过定义处理函数并将其注册到路由上Go应用可以响应各种HTTP请求
http.HandleFunc(/greeting, func(w http.ResponseWriter, r *http.Request) {fmt.Fprint(w, Hello, Go Navigator!)
})
http.ListenAndServe(:8080, nil)这段代码启动了一个HTTP服务监听8080端口并对/greeting路径的请求返回问候信息。
客户端编程
同样地Go的http包也支持发起HTTP请求。这允许Go应用作为客户端与其他HTTP服务进行交互
resp, err : http.Get(https://api.example.com/data)
if err ! nil {log.Fatalf(Cannot retrieve data: %v, err)
}
defer resp.Body.Close()
// 解析响应体...这段代码向https://api.example.com/data发起GET请求并处理返回的响应。
8.1.2 重点案例简易博客服务
在这个扩展案例中我们将构建一个简易的博客服务该服务将支持文章的创建和列出所有文章的功能。此外我们将提供一个简单的客户端示例展示如何与这个服务进行交云。
服务端实现
我们的服务端将提供两个HTTP端点一个用于接收新文章的提交POST请求另一个用于获取所有文章的列表GET请求。
// blogserver/main.gopackage mainimport (encoding/jsonfmtlognet/httpsync
)type Article struct {ID int json:idTitle string json:titleContent string json:content
}var (articles []Articlemu sync.MutexnextID 1
)func postArticleHandler(w http.ResponseWriter, r *http.Request) {var article Articleif err : json.NewDecoder(r.Body).Decode(article); err ! nil {http.Error(w, Invalid request body, http.StatusBadRequest)return}mu.Lock()article.ID nextIDnextIDarticles append(articles, article)mu.Unlock()w.WriteHeader(http.StatusCreated)json.NewEncoder(w).Encode(article)
}func listArticlesHandler(w http.ResponseWriter, r *http.Request) {mu.Lock()defer mu.Unlock()json.NewEncoder(w).Encode(articles)
}func main() {http.HandleFunc(/articles, func(w http.ResponseWriter, r *http.Request) {switch r.Method {case GET:listArticlesHandler(w, r)case POST:postArticleHandler(w, r)default:w.WriteHeader(http.StatusMethodNotAllowed)}})fmt.Println(Blog server started on :8080)log.Fatal(http.ListenAndServe(:8080, nil))
}客户端实现
客户端代码将展示如何发起请求以创建新文章以及如何获取文章列表。
// blogclient/main.gopackage mainimport (bytesencoding/jsonfmtio/ioutilnet/http
)func createArticle(title, content string) {article : map[string]string{title: title,content: content,}articleJSON, _ : json.Marshal(article)resp, err : http.Post(http://localhost:8080/articles, application/json, bytes.NewBuffer(articleJSON))if err ! nil {fmt.Println(Error creating article:, err)return}defer resp.Body.Close()body, _ : ioutil.ReadAll(resp.Body)fmt.Println(Create Article Response:, string(body))
}func getArticles() {resp, err : http.Get(http://localhost:8080/articles)if err ! nil {fmt.Println(Error fetching articles:, err)return}defer resp.Body.Close()body, _ : ioutil.ReadAll(resp.Body)fmt.Println(Articles List:, string(body))
}func main() {createArticle(Go Concurrency, Understanding Goroutines and Channels)createArticle(Go Web Programming, Building Web Apps with Go)getArticles()
}这个简易的客户端示例首先创建两篇文章然后获取并打印所有文章的列表。
运行示例
启动服务端在blogserver目录下运行go run main.go启动博客服务。运行客户端在blogclient目录下运行go run main.go通过客户端与服务端交互。
通过本案例我们探索了如何使用Go的http包来构建一个简单的HTTP服务端和客户端。这个简易博客服务的实现展示了Go在网络编程领域的强大能力提供了对HTTP请求的处理和响应的清晰示例。继续利用Go构建更多网络应用探索更广阔的编程海洋吧
8.1.3 拓展案例 1增加文章评论功能
在我们的简易博客服务中增加文章评论功能将使读者能够对文章进行互动。这要求我们在服务端添加新的逻辑来接收、存储和展示评论。
功能描述
接收评论允许用户对特定文章添加评论。存储评论将评论与对应的文章关联存储。展示评论在请求文章详情时一并返回其评论。
服务端实现
首先我们需要在服务端扩展我们的数据模型和HTTP处理函数以支持评论功能
// blogserver/main.gopackage mainimport (encoding/jsonfmtlognet/httpsync
)type Article struct {ID int json:idTitle string json:titleContent string json:contentComments []string json:comments,omitempty
}var (articles []Articlemu sync.MutexnextID 1
)// 新增添加评论的处理函数
func addCommentHandler(w http.ResponseWriter, r *http.Request) {articleID : r.URL.Query().Get(id)var comment stringif err : json.NewDecoder(r.Body).Decode(comment); err ! nil {http.Error(w, Invalid request body, http.StatusBadRequest)return}mu.Lock()defer mu.Unlock()for i, article : range articles {if article.ID articleID {articles[i].Comments append(articles[i].Comments, comment)json.NewEncoder(w).Encode(article)return}}http.Error(w, Article not found, http.StatusNotFound)
}func main() {http.HandleFunc(/articles, articlesHandler) // Assume articlesHandler handles both GET for listing and POST for creating articles.http.HandleFunc(/add_comment, addCommentHandler)fmt.Println(Blog server started on :8080)log.Fatal(http.ListenAndServe(:8080, nil))
}客户端实现
对于客户端我们需要提供一个新的函数来发起添加评论的请求
// blogclient/main.gopackage mainimport (bytesencoding/jsonfmtio/ioutilnet/httpstrconv
)func addComment(articleID int, comment string) {commentJSON, _ : json.Marshal(comment)resp, err : http.Post(http://localhost:8080/add_comment?idstrconv.Itoa(articleID), application/json, bytes.NewBuffer(commentJSON))if err ! nil {fmt.Println(Error adding comment:, err)return}defer resp.Body.Close()body, _ : ioutil.ReadAll(resp.Body)fmt.Println(Add Comment Response:, string(body))
}func main() {// 示例向ID为1的文章添加评论addComment(1, Great article!)
}通过这个扩展案例我们为简易博客服务增加了文章评论功能使得用户可以对文章进行评论并在请求文章时查看到这些评论。这个案例展示了如何在现有的Go HTTP服务中添加新的功能以及如何处理更复杂的数据关联和更新逻辑。继续探索Go在网络编程方面的能力构建更加丰富和互动的应用吧
8.1.4 拓展案例 2实现文章的搜索功能
在我们的简易博客服务中实现文章的搜索功能将极大地提升用户体验允许用户根据关键词快速找到他们感兴趣的文章。这要求我们在服务端添加一个新的端点来处理搜索请求并在文章数据中进行匹配。
功能描述
搜索文章根据用户输入的关键词返回匹配的文章列表。关键词匹配在文章的标题和内容中查找包含关键词的文章。返回结果返回匹配的文章列表给用户。
服务端实现
首先我们需要在服务端实现搜索功能的逻辑
// blogserver/main.gopackage mainimport (encoding/jsonfmtlognet/httpstringssync
)type Article struct {ID int json:idTitle string json:titleContent string json:content
}var (articles []Articlemu sync.Mutex
)// 实现搜索文章的处理函数
func searchArticlesHandler(w http.ResponseWriter, r *http.Request) {query : r.URL.Query().Get(q)if query {http.Error(w, Query parameter q is required, http.StatusBadRequest)return}mu.Lock()defer mu.Unlock()var matchedArticles []Articlefor _, article : range articles {if strings.Contains(article.Title, query) || strings.Contains(article.Content, query) {matchedArticles append(matchedArticles, article)}}json.NewEncoder(w).Encode(matchedArticles)
}func main() {http.HandleFunc(/search, searchArticlesHandler)fmt.Println(Blog server started on :8080)log.Fatal(http.ListenAndServe(:8080, nil))
}在上述代码中我们为博客服务添加了/search端点用户可以通过这个端点传递一个查询参数q来搜索文章。搜索逻辑简单地检查文章标题和内容中是否包含了查询关键词然后返回匹配的文章列表。
客户端示例
客户端可以通过发起HTTP GET请求到/search端点并传递查询参数来实现文章搜索
// 示例在客户端代码中搜索文章package mainimport (fmtio/ioutilnet/httpnet/url
)func searchArticles(query string) {baseURL : http://localhost:8080/searchqueryParams : url.Values{}queryParams.Set(q, query)searchURL : baseURL ? queryParams.Encode()resp, err : http.Get(searchURL)if err ! nil {fmt.Println(Error searching articles:, err)return}defer resp.Body.Close()body, err : ioutil.ReadAll(resp.Body)if err ! nil {fmt.Println(Error reading response body:, err)return}fmt.Printf(Search Results for %s:\n%s\n, query, string(body))
}func main() {searchArticles(Go) // 搜索包含Go的文章
}通过这个扩展案例我们为简易博客服务增加了搜索功能允许用户根据关键词搜索文章。这个案例演示了如何在Go HTTP服务中处理查询参数并根据这些参数执行简单的搜索逻辑。随着你的Go应用变得更加复杂考虑引入更高级的搜索技术如全文搜索引擎以提供更快速、更精确的搜索能力。继续探索Go在网络编程方面的强大功能开发出更加丰富和高效的网络应用。
8.2 使用 Goroutines 处理并发请求 - Go 语言的并发船队
在Go语言的并发海洋中goroutines是轻巧且强大的帆船能够高效地在处理器的海浪上航行。通过goroutinesGo应用可以同时处理数百、数千乃至更多的任务而不会因为阻塞操作而停滞不前。
8.2.1 基础知识讲解
Goroutines 的启动
goroutine是Go中实现并发的基础。启动一个goroutine就像是给帆船一阵风让它启航
go func() {// 并发执行的代码
}()只需在函数调用前加上go关键字该函数就会在新的goroutine中异步执行主程序会继续向下执行而不会等待。
并发的 HTTP 请求处理
在HTTP服务中使用goroutines可以让我们并发地处理多个请求大大提高了服务的吞吐量。每当收到一个新的请求我们就可以为其分配一个goroutine这样即使某些请求的处理时间较长也不会阻塞其他请求的处理。
8.2.2 重点案例并发下载服务
在这个案例中我们将构建一个并发下载服务该服务通过goroutines允许用户同时下载多个文件。这种并发处理模式显著提高了应用的效率特别是在处理多个网络IO密集型任务时。
服务端实现
我们的服务端提供一个HTTP接口接受一个包含多个文件URLs的请求并为每个下载任务启动一个goroutine。
// downloadservice/main.gopackage mainimport (fmtionet/httpossync
)// downloadFile函数接收文件URL和目标文件名完成文件下载
func downloadFile(url, filename string, wg *sync.WaitGroup) {defer wg.Done()resp, err : http.Get(url)if err ! nil {fmt.Printf(Failed to download %s: %v\n, url, err)return}defer resp.Body.Close()out, err : os.Create(filename)if err ! nil {fmt.Printf(Failed to create file %s: %v\n, filename, err)return}defer out.Close()_, err io.Copy(out, resp.Body)if err ! nil {fmt.Printf(Failed to write to file %s: %v\n, filename, err)return}fmt.Printf(Successfully downloaded %s to %s\n, url, filename)
}// downloadHandler处理下载请求解析请求中的URLs并启动goroutines进行下载
func downloadHandler(w http.ResponseWriter, r *http.Request) {urls : r.URL.Query()[url]if len(urls) 0 {http.Error(w, No URLs provided, http.StatusBadRequest)return}var wg sync.WaitGroupfor i, url : range urls {wg.Add(1)go downloadFile(url, fmt.Sprintf(download%d, i1), wg)}wg.Wait()fmt.Fprintln(w, All download tasks completed.)
}func main() {http.HandleFunc(/download, downloadHandler)fmt.Println(Download service started on :8080)http.ListenAndServe(:8080, nil)
}在这个实现中我们定义了downloadFile函数来处理单个文件的下载逻辑。downloadHandler函数负责解析HTTP请求中包含的多个下载URL为每个URL启动一个goroutine执行downloadFile函数并使用sync.WaitGroup等待所有下载任务完成。
测试服务
为了测试这个并发下载服务你可以使用以下方式发起一个包含多个下载URLs的请求
使用curl工具
curl http://localhost:8080/download?urlhttp://example.com/file1.jpgurlhttp://example.com/file2.jpg或者使用Postman等API测试工具发起GET请求并在请求的URL参数中添加多个url参数。
通过这个案例我们演示了如何在Go中利用goroutines和sync.WaitGroup构建一个支持并发处理的下载服务。这种模式不仅适用于文件下载还可以应用于其他需要并发执行多个任务的场景如批量数据处理、并发API请求等。随着你继续探索Go语言的并发特性你将能够构建出更加强大和高效的应用。
8.2.3 拓展案例 1并发图片处理服务
在这个案例中我们将构建一个并发图片处理服务该服务允许用户上传图片并且并行执行多种图片处理任务如调整大小、应用滤镜等。利用goroutines实现并发处理可以显著提高服务的处理效率。
功能描述
图片上传允许用户上传图片到服务。并发图片处理对上传的图片并发执行多种处理任务。返回处理结果将处理后的图片保存并提供下载链接或直接返回给用户。
服务端实现
为了简化示例我们假设图片已经上传到服务器上的某个目录服务端的任务是读取这些图片并并发地进行处理。
首先我们需要一个库来帮助我们处理图片这里我们使用github.com/disintegration/imaging库
go get -u github.com/disintegration/imaging接着实现图片处理服务的核心逻辑
// imageprocessingservice/main.gopackage mainimport (fmtgithub.com/disintegration/imagingnet/httpospath/filepathsync
)func processImage(filePath string, wg *sync.WaitGroup) {defer wg.Done()srcImage, err : imaging.Open(filePath)if err ! nil {fmt.Printf(Failed to open image %s: %v\n, filePath, err)return}// 示例调整图片大小为200x200并应用高斯模糊滤镜dstImage : imaging.Resize(srcImage, 200, 200, imaging.Lanczos)dstImage imaging.Blur(dstImage, 2.0)outputPath : filepath.Join(processed, filepath.Base(filePath))err imaging.Save(dstImage, outputPath)if err ! nil {fmt.Printf(Failed to save processed image %s: %v\n, outputPath, err)return}fmt.Printf(Processed and saved image to %s\n, outputPath)
}func imageHandler(w http.ResponseWriter, r *http.Request) {var wg sync.WaitGroup// 假设图片存储在./uploads目录files, err : filepath.Glob(./uploads/*)if err ! nil {http.Error(w, Failed to list images, http.StatusInternalServerError)return}for _, file : range files {wg.Add(1)go processImage(file, wg)}wg.Wait()fmt.Fprintln(w, All images processed.)
}func main() {http.HandleFunc(/process-images, imageHandler)fmt.Println(Image processing service started on :8080)http.ListenAndServe(:8080, nil)
}在上述代码中processImage函数负责打开一个图片文件执行一系列处理任务在这个示例中是调整大小和应用模糊滤镜然后保存处理后的图片到processed目录。imageHandler函数并发地对uploads目录中的所有图片调用processImage函数。
测试服务
启动服务后你可以通过向/process-images端点发送HTTP请求来触发图片处理过程。这可以通过浏览器访问或使用工具如curl进行
curl http://localhost:8080/process-images这个并发图片处理服务展示了如何利用goroutines提高处理效率通过并行处理来快速完成大量的图片处理任务。你可以根据具体需求添加更多的图片处理功能如调整亮度、对比度或者应用更复杂的图像分析算法。继续探索Go语言的并发特性为你的应用带来更强大的处理能力。
8.2.4 拓展案例 2实时股票行情服务
在这个案例中我们将构建一个实时股票行情服务该服务使用goroutines并发查询多个股票代码的实时价格并将查询结果合并后返回给客户端。这种并发处理方式能够显著提高数据获取的速度特别适合需要实时响应的金融应用。
功能描述
并发查询股票价格对于客户端提供的股票代码列表服务端并发查询每个股票的实时价格。合并查询结果将所有查询结果合并后一次性返回给客户端。错误处理对于查询失败的股票代码返回错误信息。
服务端实现
为了模拟股票价格查询我们假设有一个简单的函数fetchStockPrice模拟从外部API获取股票价格。实际应用中你需要替换为真实的股票价格API调用。
// stockservice/main.gopackage mainimport (encoding/jsonfmtmath/randnet/httpsynctime
)type StockPrice struct {Symbol string json:symbolPrice float64 json:priceError string json:error,omitempty
}func fetchStockPrice(symbol string) StockPrice {// 模拟网络延迟time.Sleep(time.Duration(rand.Intn(300)) * time.Millisecond)// 模拟偶尔的查询失败if rand.Intn(10) 7 {return StockPrice{Symbol: symbol, Error: Failed to fetch price}}// 模拟股票价格return StockPrice{Symbol: symbol, Price: rand.Float64() * 100}
}func stockHandler(w http.ResponseWriter, r *http.Request) {symbols : r.URL.Query()[symbol]var wg sync.WaitGroupresults : make([]StockPrice, len(symbols))for i, symbol : range symbols {wg.Add(1)go func(i int, symbol string) {defer wg.Done()results[i] fetchStockPrice(symbol)}(i, symbol)}wg.Wait()json.NewEncoder(w).Encode(results)
}func main() {rand.Seed(time.Now().UnixNano())http.HandleFunc(/stocks, stockHandler)fmt.Println(Stock service started on :8080)http.ListenAndServe(:8080, nil)
}在这段代码中stockHandler函数接收一个包含股票代码的查询参数为每个股票代码启动一个goroutine执行fetchStockPrice函数并发地获取股票价格。使用sync.WaitGroup等待所有的查询任务完成然后将结果合并后以JSON格式返回给客户端。
测试服务
你可以通过向/stocks端点发送HTTP GET请求并附带股票代码作为查询参数来测试服务
curl http://localhost:8080/stocks?symbolAAPLsymbolGOOGLsymbolMSFT这个简单的实时股票行情服务展示了如何利用Go的并发特性来提高数据处理的速度。通过goroutines并发执行任务和sync.WaitGroup来同步任务结果我们可以构建出响应迅速、性能卓越的实时服务。在实际应用中你可以将此模式应用于任何需要并发数据获取和处理的场景充分发挥Go在并发编程方面的优势。
8.3 WebSocket 与 RPC - Go 语言的深海通信线
在Go语言的并发海洋中WebSocket和RPC (Remote Procedure Call) 是两种深海通信线允许我们跨越深渊进行实时和跨服务的通信。
8.3.1 基础知识讲解
WebSocket
WebSocket提供了一个全双工通信渠道允许客户端和服务器之间建立持久连接并实时交换数据。这对于需要实时功能的应用来说非常有用比如在线聊天室、实时数据仪表板等。
在Go中gorilla/websocket是一个流行的库用于在HTTP服务器上添加WebSocket支持。
RPC
RPC允许客户端执行远程服务器上的函数就像是执行本地函数一样隐藏了网络请求的复杂性。Go标准库中的net/rpc包提供了构建RPC系统的基础。
8.3.2 重点案例实时聊天应用
在这个扩展案例中我们将构建一个简单的实时聊天应用使用WebSocket实现客户端和服务器之间的实时通信。这个应用将允许用户通过Web浏览器连接到聊天服务器发送消息并实时接收来自其他用户的消息。
服务端实现
我们使用gorilla/websocket库来处理WebSocket连接。首先需要安装这个库
go get -u github.com/gorilla/websocket然后我们实现聊天服务器的核心逻辑
// chatserver/main.gopackage mainimport (github.com/gorilla/websocketnet/httplog
)var clients make(map[*websocket.Conn]bool) // 连接到服务器的客户端
var broadcast make(chan []byte) // 广播通道var upgrader websocket.Upgrader{CheckOrigin: func(r *http.Request) bool {return true},
}func main() {http.HandleFunc(/ws, handleConnections)go handleMessages()log.Println(Chat server started on :8080)log.Fatal(http.ListenAndServe(:8080, nil))
}func handleConnections(w http.ResponseWriter, r *http.Request) {ws, err : upgrader.Upgrade(w, r, nil)if err ! nil {log.Fatal(err)}defer ws.Close()clients[ws] truefor {_, msg, err : ws.ReadMessage()if err ! nil {log.Printf(Error: %v, err)delete(clients, ws)break}broadcast - msg}
}func handleMessages() {for {msg : -broadcastfor client : range clients {err : client.WriteMessage(websocket.TextMessage, msg)if err ! nil {log.Printf(Error: %v, err)client.Close()delete(clients, client)}}}
}在这个实现中handleConnections函数处理新的WebSocket连接读取来自客户端的消息并将它们放入broadcast通道。handleMessages函数监听broadcast通道将接收到的消息发送给所有连接的客户端。
客户端实现
客户端可以是一个简单的HTML页面使用JavaScript与WebSocket服务器进行通信
!-- chatclient/index.html --!DOCTYPE html
html langen
headmeta charsetUTF-8titleGo Chat App/titlescriptdocument.addEventListener(DOMContentLoaded, function() {var ws new WebSocket(ws://localhost:8080/ws);var messages document.getElementById(messages);ws.onmessage function(event) {var message document.createElement(p);message.textContent event.data;messages.appendChild(message);};document.getElementById(sendBtn).onclick function() {var message document.getElementById(messageInput).value;ws.send(message);document.getElementById(messageInput).value ;};});/script
/head
bodydiv idmessages/divinput idmessageInput typetextbutton idsendBtnSend/button
/body
/html这个HTML页面包含一个消息列表、一个文本输入框和一个发送按钮。当用户点击发送按钮时当前的消息会通过WebSocket发送到服务器并且清空输入框。当服务器通过WebSocket发送消息时它们会被添加到页面的消息列表中。
运行示例
启动服务端在chatserver目录下运行go run main.go启动聊天服务器。打开客户端在浏览器中打开chatclient/index.html文件连接到聊天服务器。
通过这个案例我们展示了如何使用Go和WebSocket构建一个简单的实时聊天应用。这个应用能够让多个用户通过Web界面实时交换消息体验到实时通信的魅力。随着你继续探索WebSocket和Go在网络编程方面的更多可能性你将能够构建更加复杂和强大的实时Web应用。
8.3.3 拓展案例 1股票行情实时更新服务
在这个案例中我们将构建一个基于WebSocket的股票行情实时更新服务。该服务允许客户端通过WebSocket订阅特定的股票代码并在股票价格发生变动时接收实时更新。
服务端实现
为了简化演示我们假设股票价格的变动是随机模拟的。在实际应用中你可能需要连接到真实的股市数据API来获取实时行情。
首先安装gorilla/websocket库
go get -u github.com/gorilla/websocket接着实现WebSocket服务端逻辑
// stockservice/main.gopackage mainimport (encoding/jsongithub.com/gorilla/websocketlogmath/randnet/httptime
)var upgrader websocket.Upgrader{CheckOrigin: func(r *http.Request) bool {return true},
}type StockUpdate struct {Symbol string json:symbolPrice float64 json:price
}func handleConnections(w http.ResponseWriter, r *http.Request) {ws, err : upgrader.Upgrade(w, r, nil)if err ! nil {log.Fatal(err)}defer ws.Close()// 模拟股票代码列表stocks : []string{AAPL, GOOGL, MSFT}for {// 等待客户端消息并读取订阅的股票代码_, msg, err : ws.ReadMessage()if err ! nil {log.Printf(error: %v, err)break}symbol : string(msg)// 如果订阅的股票代码在模拟的列表中开始发送更新for _, s : range stocks {if s symbol {for {// 随机生成股票价格并发送price : rand.Float64() * 1000update : StockUpdate{Symbol: symbol, Price: price}updateJSON, err : json.Marshal(update)if err ! nil {log.Printf(error: %v, err)break}if err : ws.WriteMessage(websocket.TextMessage, updateJSON); err ! nil {log.Printf(error: %v, err)break}// 每隔一秒发送一次更新time.Sleep(1 * time.Second)}break}}}
}func main() {rand.Seed(time.Now().UnixNano())http.HandleFunc(/ws, handleConnections)log.Println(Stock service started on :8080)log.Fatal(http.ListenAndServe(:8080, nil))
}客户端示例
客户端可以是一个简单的HTML页面通过JavaScript与WebSocket服务器建立连接并发送订阅请求
!-- stockclient/index.html --!DOCTYPE html
html
headtitleReal-time Stock Updates/titlescriptdocument.addEventListener(DOMContentLoaded, () {const ws new WebSocket(ws://localhost:8080/ws);ws.onopen () {console.log(Connected to the server);// 订阅AAPL股票的更新ws.send(AAPL);};ws.onmessage (event) {const stockUpdate JSON.parse(event.data);console.log(Stock update for ${stockUpdate.symbol}: $${stockUpdate.price.toFixed(2)});};ws.onerror (error) {console.log(WebSocket error: error.message);};ws.onclose () {console.log(Disconnected from the server);};});/script
/head
bodyh1Real-time Stock Updates/h1pOpen the console to view the stock updates./p
/body
/html在这个HTML页面中当页面加载完成后客户端通过WebSocket连接到服务器并发送一个订阅请求在此例中为AAPL股票。然后它将监听服务器发送的更新并在控制台中显示更新的股票价格。
运行示例
启动服务端在stockservice目
录下运行go run main.go启动股票行情更新服务。
打开客户端在Web浏览器中打开stockclient/index.html文件并查看浏览器控制台以接收实时的股票价格更新。
通过这个拓展案例我们演示了如何使用WebSocket在Go中实现一个实时的股票行情更新服务。客户端可以订阅感兴趣的股票代码并接收关于这些股票的实时价格更新展现了WebSocket在构建实时通信应用中的强大能力。继续探索WebSocket和Go的其他网络编程特性为你的应用带来更加丰富的实时交互体验。
8.3.4 拓展案例 2远程系统监控
在这个案例中我们将构建一个基于RPC的远程系统监控工具允许管理员从中央服务器调用远程机器上的函数以获取系统状态信息如CPU使用率、内存使用等。这个工具将使用Go的net/rpc包来实现RPC通信。
功能描述
远程获取系统状态允许管理员远程调用函数获取目标机器的系统状态信息。支持多种状态查询支持查询CPU使用率、内存使用情况等不同类型的系统状态。简单的认证机制实现一个简单的认证机制确保只有授权的用户可以查询系统状态。
服务端实现
首先我们需要定义提供的远程调用方法和服务
// monitorserver/main.gopackage mainimport (errorsnetnet/rpcruntime
)type Args struct {AuthToken string
}type SystemStats struct {CPU stringMemory string
}type Monitor intfunc (t *Monitor) GetSystemStats(args *Args, reply *SystemStats) error {if args.AuthToken ! secret {return errors.New(unauthorized)}// 模拟获取系统状态reply.CPU 2.4 GHzreply.Memory 8 GBreturn nil
}func main() {monitor : new(Monitor)rpc.Register(monitor)rpc.HandleHTTP()l, err : net.Listen(tcp, :1234)if err ! nil {panic(err)}for {conn, err : l.Accept()if err ! nil {continue}go rpc.ServeConn(conn)}
}在这个实现中我们定义了一个Monitor类型它有一个方法GetSystemStats用于远程获取系统状态。我们使用了一个简单的认证机制通过检查传递的AuthToken来授权访问。
客户端实现
客户端将通过RPC调用服务端的GetSystemStats方法来获取系统状态
// monitorclient/main.gopackage mainimport (fmtlognet/rpc
)type Args struct {AuthToken string
}type SystemStats struct {CPU stringMemory string
}func main() {client, err : rpc.DialHTTP(tcp, localhost:1234)if err ! nil {log.Fatal(Dialing:, err)}args : Args{secret}var reply SystemStatserr client.Call(Monitor.GetSystemStats, args, reply)if err ! nil {log.Fatal(Monitor error:, err)}fmt.Printf(CPU: %s\nMemory: %s\n, reply.CPU, reply.Memory)
}在这个客户端实现中我们创建了一个RPC客户端连接到服务端并调用Monitor.GetSystemStats方法传递认证令牌并获取系统状态信息。
运行示例
启动服务端在monitorserver目录下运行go run main.go启动系统监控服务。运行客户端在monitorclient目录下运行go run main.go来从服务端获取系统状态信息。
通过这个拓展案例我们演示了如何使用Go的net/rpc包实现一个基于RPC的远程系统监控工具。这个工具允许管理员远程获取系统状态信息展现了RPC在构建分布式系统和服务通信中的实用性。继续探索Go的RPC和其他网络编程特性为你的分布式应用提供强大的后端支持。