此示例 tcp 套接字编程事件序列安全吗?

我计划提供两项服务。

  1. 用 Ruby 编写的 HTTP REST 服务

  2. 用 Go 编写的 JSON RPC 服务

Ruby 服务将打开一个到 Go JSON RPC 服务的 TCP 套接字连接。它将为收到的每个传入 HTTP 请求执行此操作。它将通过套接字向 Go 服务发送一些数据,该服务随后将相应的数据发送回套接字。

去代码

Go 服务 go 看起来像这样(简化):

srv := new(service.App) // this would expose a Process method


rpc.Register(srv)


listener, err := net.Listen("tcp", ":8080")

if err != nil {

    // handle error

}


for {

    conn, err := listener.Accept()

    if err != nil {

        // handle error

    }


    go jsonrpc.ServeConn(conn)

}

请注意,我们使用 goroutine 为传入连接提供服务,因此我们可以并发处理请求。


红宝石代码

下面是一段简单的 Ruby 代码片段,它演示了(理论上)我将数据发送到 Go 服务的方式:


require "socket"

require "json"


socket = TCPSocket.new "localhost", "8080"


b = {

  :method => "App.Process",

  :params => [{ :Config => JSON.generate({ :foo => :bar }) }],

  :id     => "0"

}


socket.write(JSON.dump(b))


response = JSON.load socket.readline

我担心的是:这会是一个安全的事件序列吗?


我不是在问这是否是“线程安全的”,因为我不担心跨 go 例程操纵共享内存。我更关心我的 Ruby HTTP 服务是否会取回它期望的数据?


如果我有两个并行请求进入我的 HTTP 服务(或者 Ruby 应用程序托管在负载均衡器之后,因此HTTP 服务的不同实例正在处理多个请求),那么我可以让实例 A 将消息 Foo 发送到 Go服务; 而实例 B 发送消息 Bar。


Go 服务内部的业务逻辑将根据其输入返回不同的响应,因此我想确保 Ruby 实例 A 为 Foo 返回正确的响应,而 B 为 Bar 返回正确的响应。


我假设套接字连接更像是一个队列,因为如果实例 A 先向 Go 服务发出请求,然后B 这样做,但 B 无论出于何种原因响应更快,那么 Go 服务会将 B 的响应写入套接字并且 Ruby 应用程序的实例 A 最终将读取错误的套接字数据(这显然只是一种可能的情况,因为我可能很幸运并且让实例 B 在实例 A 之前读取了套接字数据)。


解决方案?

我不确定这个问题是否有简单的解决方案。除非我不使用 TCP 套接字或 RPC 而是依赖 Go 服务中的标准 HTTP。但我想要 TCP 的性能和更少的开销。


我担心设计可能会变得更加复杂,因为可能必须实现一个外部队列作为与 Ruby 服务同步响应的一种方式。


可能是因为我的 Ruby 服务本质上是同步的(HTTP 响应/请求),所以我别无选择,只能为 Go 服务切换到 HTTP。


但是我想先与社区进行仔细检查,以防万一我遗漏了一些明显的东西。


蓝山帝景
浏览 176回答 1
1回答

HUX布斯

是的,如果您每次都创建一个新连接,这是安全的。也就是说,您的方法存在潜在问题:TCP 连接建立起来相当昂贵,因此您可能希望通过连接池重用连接如果您同时发出太多请求,您将耗尽端口/打开文件描述符,这将导致您的程序崩溃您没有任何超时,因此最终可能会出现永远无法完成的孤立 TCP 连接(由于 Go 方面的问题或网络问题)我认为最好使用 HTTP(尽管有开销),因为已经编写了库来处理这些问题。HTTP 也更易于调试,因为您只需 curl 一个端点来测试它。我个人可能会选择gRPC。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go