Go Server #私藏项目实操分享#

举报
宇宙之一粟 发表于 2022/01/15 01:22:31 2022/01/15
【摘要】 Servers 用Go编写网络服务器是非常容易的。我们首先看一下如何创建一个TCP服务器: package mainimport ( "encoding/gob" "fmt" "net")func server() { ...

Servers

用Go编写网络服务器是非常容易的。我们首先看一下如何创建一个TCP服务器:

package mainimport (        "encoding/gob"    "fmt"    "net")func server() {    // listen on a port    ln, err := net.Listen("tcp", ":9999")    if err != nil {        fmt.Println(err)    return}    for {        // accept a connection        c, err := ln.Accept()        if err != nil {            fmt.Println(err)            continue        }        // handle the connection        go handleServerConnection(c)    }}func handleServerConnection(c net.Conn) {    // receive the message    var msg string    err := gob.NewDecoder(c).Decode(&msg)    if err != nil {        fmt.Println(err)    } else {        fmt.Println("Received", msg)    }    c.Close()}func client() {    // connect to the server    c, err := net.Dial("tcp", "127.0.0.1:9999")    if err != nil {        fmt.Println(err)        return    }    // send the message    msg := "Hello World"    fmt.Println("Sending", msg)    err = gob.NewEncoder(c).Encode(msg)    if err != nil {        fmt.Println(err)    }    c.Close()}func main() {    go server()    go client()    var input string    fmt.Scanln(&input)}
        

这个例子使用了encoding/gob包,它可以很容易地对Go的数值进行编码,以便其他G程序(或者在这种情况下是同一个Go程序)可以读取它们。在encoding下面的包(如encoding/json)以及第三方包中都有其他的编码方式。(例如,我们可以使用 labix.org/v2/mgo/bson来支持bson)。

HTTP

HTTP服务器的设置和使用更加容易。

package mainimport (    "io"    "net/http")func hello(res http.ResponseWriter, req *http.Request) {    res.Header().Set(        "Content-Type",        "text/html",    )    io.WriteString(        res,        `<doctype html><html>    <head>        <title>Hello World</title>    </head>    <body>        Hello World!    </body></html>`,    )}func main() {    http.HandleFunc("/hello", hello)    http.ListenAndServe(":9000", nil)}
        

HandleFunc通过调用给定的函数来处理一个URL路由(/hello)。我们还可以通过使用FileServer来处理静态文件

http.Handle(    "/assets/",    http.StripPrefix(        "/assets/",        http.FileServer(http.Dir("assets")),    ),)
        

RPC

net/rpc(远程过程调用)和 ​​net/rpc/jsonrpc​​ 软件包提供了一种简单的方法来公开方法,因此它们可以通过网络被调用。 (而不是仅仅在运行它们的程序中)。

package mainimport (    "fmt"    "net"    "net/rpc")type Server struct{}func (this *Server) Negate(i int64, reply *int64) error {    *reply = -i    return nil}func server() {    rpc.Register(new(Server))    ln, err := net.Listen("tcp", ":9999")    if err != nil {        fmt.Println(err)        return    }    for {        c, err := ln.Accept()        if err != nil {            continue        }        go rpc.ServeConn(c)    }}func client() {    c, err := rpc.Dial("tcp", "127.0.0.1:9999")    if err != nil {        fmt.Println(err)        return    }    var result int64    err = c.Call("Server.Negate", int64(999),        &result)    if err != nil {        fmt.Println(err)    } else {        fmt.Println("Server.Negate(999) =",            result)    }}func main() {    go server()    go client()    var input string    fmt.Scanln(&input)}
        

这个程序与TCP的例子相似,只是现在我们创建了一个对象来保存我们想要公开的所有方法,并且我们从 客户端调用否定方法。更多细节请参见 net/rpc 的文档。

剖析命令行参数

当我们在终端上调用一个命令时,有可能将该命令的参数传递给它。我们已经在go命令中看到了这一点

​go run myfile.go​

run 和 myfile.go 是参数。我们还可以将标志给一个命令。

​go run -v myfile.go​

标志包允许我们解析发送给我们程序的参数和标志。下面是一个生成0到6之间的数字的程序实例。我们可以通过发送一个标志(max=100)来改变最大值 程序

package mainimport ("fmt";"flag";"math/rand")func main() {    // Define flags    maxp := flag.Int("max", 6, "the max value")    // Parse    flag.Parse()    // Generate a number between 0 and max    fmt.Println(rand.Intn(*maxp))}
        

任何额外的非flag参数都可以通过 ​​flag.Args()​​ 来获取。用 flag.Args() 检索,它返回一个字符串数组。

同步原语

在Go中处理并发和同步的首选方式是通过goroutines和channel,正如第10章所讨论的。然而,Go也提供了更多传统的多线程例程,如sync 和 sync/atomic 包中提供了更为传统的多线程例程.

Mutexes

互斥锁(mutex)将一段代码锁定在一个单一的线程上。锁定一段代码,用于保护共享资源不受非原子操作的影响。用于保护共享资源免受非原子操作的影响。下面是 一个互斥锁的例子:

package mainimport (    "fmt"    "sync"    "time")func main() {    m := new(sync.Mutex)    for i := 0; i < 10; i++ {        go func(i int) {            m.Lock()            fmt.Println(i, "start")            time.Sleep(time.Second)            fmt.Println(i, "end")            m.Unlock()        }(i)    }    var input string    fmt.Scanln(&input)}
        

当 ​​mutex (m)​​ 被锁定时,任何其他试图锁定的行为都会被阻止,直到它被解锁。在使用mutexes或sync/atomic包中提供的同步原语时,应该非常小心。

传统的多线程编程是很困难的;很容易犯错,而且这些错误很难发现,因为它们可能取决于非常具体的、相对罕见的、难以重现的一系列情况。Go最大的优势之一是它所提供的并发功能比线程和锁更容易理解和正确使用。

文章来源: blog.csdn.net,作者:宇宙之一粟,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/yuzhou_1shu/article/details/122476750

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。