英文:
Go - TCP Client Often Misses Secondary JSON Reply
问题
我正在尝试编写一个TCP客户端,向本地托管的TCP服务器发送一个JSON RPC。服务器应立即返回两个回复。
TCP服务器托管在端口60000上。
以下是客户端代码的样子:
package main
import (
"fmt"
"log"
"bufio"
"net"
)
func main() {
d := net.Dialer{ }
c, err := d.Dial("tcp", "127.0.0.1:60000")
if err != nil {
log.Println(err)
return
}
data := `{"id": 1,"method":"mining.configure","params": [["version-rolling"],{"version-rolling.mask": "1fffe000","version-rolling.min-bit-count": 16}]}`
fmt.Fprintf(c, data+"\n")
for {
message, _ := bufio.NewReader(c).ReadString('\n')
fmt.Println(message)
}
}
这是我发送的内容("data"变量)
{
"id": 1,
"method":"mining.configure",
"params": [["version-rolling"],
{"version-rolling.mask": "1fffe000",
"version-rolling.min-bit-count": 16}]
}
这是预期的回复:
{"error":null,"id":1,"result":{"version-rolling":true,"version-rolling.mask":"1fffe000"}}
{"id":null,"method":"mining.set_version_mask","params":["1fffe000"]}
大多数情况下,我只收到第一个回复(带有"result"字段),而没有带有"method"字段的第二个JSON。有时我会同时收到两个回复。
但通常的回复是:
{"error":null,"id":1,"result":{"version-rolling":true,"version-rolling.mask":"1fffe000"}}
我知道当代码变得不确定时,这是由于异步问题引起的。
但是,我遇到的每个初学者教程都教授了这个编写TCP客户端的确切结构。它缺少了什么?
我已经使用Python和Twisted框架对服务器进行了大量的相同RPC调用测试,我100%的时间都能得到两个回复。这使我确信问题出在我的客户端代码中,而不是服务器上。
英文:
I'm trying to write a TCP client that sends out a JSON RPC to a locally hosted TCP server. The server should immediately return two replies.
The TCP server is hosted on port 60000.
This is what the client code looks like:
package main
import (
"fmt"
"log"
"bufio"
"net"
)
func main() {
d := net.Dialer{ }
c, err := d.Dial("tcp", "127.0.0.1:60000")
if err != nil {
log.Println(err)
return
}
data := `{"id": 1,"method":"mining.configure","params": [["version-rolling"],{"version-rolling.mask": "1fffe000","version-rolling.min-bit-count": 16}]}`
fmt.Fprintf(c, data+"\n")
for {
message, _ := bufio.NewReader(c).ReadString('\n')
fmt.Println(message)
}
}
This is what I'm sending out ( the "data" variable )
{
"id": 1,
"method":"mining.configure",
"params": [["version-rolling"],
{"version-rolling.mask": "1fffe000",
"version-rolling.min-bit-count": 16}]
}
This is the expected reply:
{"error":null,"id":1,"result":{"version-rolling":true,"version-rolling.mask":"1fffe000"}}
{"id":null,"method":"mining.set_version_mask","params":["1fffe000"]}
Most of the time I only get the first reponse (has the result "field") without the second JSON that has the "method" field. Sometimes I get both.
But this is the usual reply:
{"error":null,"id":1,"result":{"version-rolling":true,"version-rolling.mask":"1fffe000"}}
I know that when code becomes non-deterministic like this it's because of an asynchronous issue going on.
But every beginner tutorial I encountered teaches this exact structure for writing a TCP client. What's missing from it?
I've tested the same RPC call to the server extensively with Python with the Twisted framework and I get back the both replies 100% of the time. This makes me certain the issue is within my client code and not the server.
答案1
得分: 3
根据接收数据的时间,ReadString函数可能会缓冲超过\n
的数据。问题中的代码在每次循环迭代时都会丢弃读取器和读取器中缓冲的数据。
为了避免丢弃数据,可以在循环内部创建读取器,并在循环中重复使用:
r := bufio.NewReader(c)
for {
message, _ := r.ReadString('\n')
fmt.Println(message)
}
英文:
Depending on the timing that data is received, the call to ReadString can buffer data past the \n
. The code in the question discards the reader and data buffered in the reader on each iteration of the loop.
To avoid discarding data, create the reader once and reuse inside the loop:
r := bufio.NewReader(c)
for {
message, _ := r.ReadString('\n')
fmt.Println(message)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论