创建服务器

创建 http 服务器

  1. package main
  2.  
  3. import (
  4. "net/http"
  5.  
  6. "github.com/hprose/hprose-golang/rpc"
  7. )
  8.  
  9. func hello(name string) string {
  10. return "Hello " + name + "!"
  11. }
  12.  
  13. func main() {
  14. service := rpc.NewHTTPService()
  15. service.AddFunction("hello", hello)
  16. http.ListenAndServe(":8080", service)
  17. }

创建 fasthttp 服务器

  1. package main
  2.  
  3. import (
  4. rpc "github.com/hprose/hprose-golang/rpc/fasthttp"
  5. "github.com/valyala/fasthttp"
  6. )
  7.  
  8. func hello(name string) string {
  9. return "Hello " + name + "!"
  10. }
  11.  
  12. func main() {
  13. service := rpc.NewFastHTTPService()
  14. service.AddFunction("hello", hello)
  15. fasthttp.ListenAndServe(":8080", service.ServeFastHTTP)
  16. }

对比上面两个服务,我们发现服务函数(方法)的编写和发布上是没有区别的,区别只在于创建服务器所使用的构造函数和启动服务器所使用的库。

上面的例子发布的是单个的函数,实际上不仅仅可以发布单个的函数,还可以同时发布多个函数,多个方法,多个结构体对象等等,后面我们会详细介绍这些。这里以发布 hello 函数为例,目的是为了突出创建服务器这个重点。

注意 import 的路径是有所不同的。

创建 TCP 服务器

  1. package main
  2.  
  3. import (
  4. "github.com/hprose/hprose-golang/rpc"
  5. )
  6.  
  7. func hello(name string) string {
  8. return "Hello " + name + "!"
  9. }
  10.  
  11. func main() {
  12. server := rpc.NewTCPServer("tcp4://0.0.0.0:4321/")
  13. server.AddFunction("hello", hello)
  14. server.Start()
  15. }

同样服务编写和发布没有区别,区别只在于构造函数和服务的启动。在这里我们创建 TCP 服务器时,使用的是 TCPServer 而不是 TCPService,这可以省去自己创建监听 TCP 服务器的麻烦,但是如果你愿意自己来做这部分也可以,使用 TCPService 就可以了。例如:

  1. service := rpc.NewTCPService()
  2. service.AddFunction("hello", hello)
  3. addr, _ := net.ResolveTCPAddr("tcp", ":4321")
  4. listener, _ := net.ListenTCP("tcp", addr)
  5. service.ServeTCP(listener)

当然上面这个使用 service 发布服务的代码只是一个最简单的例子,它并不完备,如果你要自己实现一个完备的 TCP 服务器,还需要做好多工作,上面的代码只是为了说明 servicelistener 如何结合。

创建 Unix Socket 服务器

  1. package main
  2.  
  3. import (
  4. "github.com/hprose/hprose-golang/rpc"
  5. )
  6.  
  7. func hello(name string) string {
  8. return "Hello " + name + "!"
  9. }
  10.  
  11. func main() {
  12. server := rpc.NewUnixServer("unix:/tmp/my.sock")
  13. server.AddFunction("hello", hello)
  14. server.Start()
  15. }

这个跟 TCP 服务很类似,不多作介绍了。关于 UnixService 的用法同上面的 TCPService 也是类似的,也略过不做介绍了。

创建 WebSocket 服务器

  1. package main
  2.  
  3. import (
  4. "net/http"
  5.  
  6. rpc "github.com/hprose/hprose-golang/rpc/websocket"
  7. )
  8.  
  9. func hello(name string) string {
  10. return "Hello " + name + "!"
  11. }
  12.  
  13. func main() {
  14. service := rpc.NewWebSocketService()
  15. service.AddFunction("hello", hello)
  16. http.ListenAndServe(":8080", service)
  17. }

这个跟 HTTP 服务器的创建很类似,而且这个 WebSocket 的 hprose 服务器,同时也是一个 HTTP 的 hprose 服务器,它可以同时接受 HTTP 和 WebSocket 的 hprose 客户端请求。

注意 import 的路径是有所不同的。

跟 gin 框架结合

HTTP\HTTPS 和 WebSocket 服务并没有单独实现 Server,而只是实现了 Service,所以,这些服务器的启动与关闭依赖于你所使用的 http 库或框架。上面在创建服务器一节中,我们已经介绍了使用 net/http 和 fasthttp 如何来创建服务器。下面我们再举一个在 gin 框架下面如何发布服务的例子:

  1. package main
  2.  
  3. import (
  4. "github.com/hprose/hprose-golang/rpc"
  5. "gopkg.in/gin-gonic/gin.v1"
  6. )
  7.  
  8. func hello(name string) string {
  9. return "Hello " + name + "!"
  10. }
  11.  
  12. func main() {
  13. service := rpc.NewHTTPService()
  14. service.AddFunction("hello", hello)
  15. router := gin.Default()
  16. router.Any("/path", func(c *gin.Context) {
  17. service.ServeHTTP(c.Writer, c.Request)
  18. })
  19. router.Run(":8080")
  20. }

上面代码中的 "/path" 可以是任意你希望发布 hprose 服务的路径,一个入口,所有的 Hprose 服务都从这里开始。

WebSocket 服务器跟上面的写法类似,只要把 rpc.NewHTTPService() 换成 rpc.NewWebSocketService() 就可以了,另外注意修改一下导入包的路径。

跟 echo 框架结合

  1. package main
  2.  
  3. import (
  4. "github.com/hprose/hprose-golang/rpc"
  5. "github.com/labstack/echo"
  6. )
  7.  
  8. func hello(name string) string {
  9. return "Hello " + name + "!"
  10. }
  11.  
  12. func main() {
  13. service := rpc.NewHTTPService()
  14. service.AddFunction("hello", hello)
  15. e := echo.New()
  16. e.Any("/path", echo.WrapHandler(service))
  17. e.Start(":8080")
  18. }

上面代码中的 "/path" 可以是任意你希望发布 hprose 服务的路径,一个入口,所有的 Hprose 服务都从这里开始。

WebSocket 服务器跟上面的写法类似,只要把 rpc.NewHTTPService() 换成 rpc.NewWebSocketService() 就可以了。另外注意修改一下导入包的路径。

跟 beego 框架结合

  1. package main
  2.  
  3. import (
  4. "github.com/astaxie/beego"
  5. "github.com/hprose/hprose-golang/rpc"
  6. )
  7.  
  8. func hello(name string) string {
  9. return "Hello " + name + "!"
  10. }
  11.  
  12. func main() {
  13. service := rpc.NewHTTPService()
  14. service.AddFunction("hello", hello)
  15. beego.Handler("/path", service)
  16. beego.Run()
  17. }

发布 WebSocket 服务的方式,跟 gin 和 echo 一样。

跟 iris 框架结合

  1. package main
  2.  
  3. import (
  4. rpc "github.com/hprose/hprose-golang/rpc/fasthttp"
  5. "github.com/kataras/iris"
  6. )
  7.  
  8. func hello(name string) string {
  9. return "Hello " + name + "!"
  10. }
  11.  
  12. func main() {
  13. service := rpc.NewFastHTTPService()
  14. service.AddFunction("hello", hello)
  15. iris.Any("/path", func(c *iris.Context) {
  16. service.ServeFastHTTP(c.RequestCtx)
  17. })
  18. iris.Listen(":8080")
  19. }

跟 gin 和 echo 不同,iris 是基于 fasthttp 的,所以这里创建的是 FastHTTPService。注意导入包的路径。

Socket 服务器的启动与关闭

下面来介绍一下关于 TCPServerUnixServer 的启动与关闭。

Start 和 Handle 方法区别

TCPServerUnixServer 都包含 StartHandle 两个方法,它俩的功能很接近,都是用于启动服务。区别是:

Handle 启动服务是非阻塞的,Handle 启动服务后,代码会继续执行。

Start 启动服务之后会阻塞不再向下执行。Start 启动之后,会监听以下的系统信号:

  • syscall.SIGHUP
  • syscall.SIGQUIT
  • syscall.SIGTERM
  • syscall.SIGINT
  • syscall.SIGKILL
    当收到 syscall.SIGHUP 信号时,服务会重启。当收到其它几个信号时,服务会关闭。

Stop 和 Close 方法的区别

Stop 对应 Start 方法,Close 对应 Handle 方法。即,Stop 方法实际上是发送一个 syscall.SIGQUIT 信号给 Start 启动的服务器以结束服务,对于直接使用 Handle 方法启动的服务,Stop 方法无效。使用 Close 方法可以关闭使用 Handle 方法启动的服务。

Restart 方法

Restart 这个也是用于重启使用 Start 方法启动的服务的,对于直接使用 Handle 方法启动的服务无效。