- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
这个问题是关于 go 和它的 net 包的。
我写了一个简单的 tcp 服务器处理一些 RPC。客户端使用 chan net.Conn
来管理客户端的所有 tcp 连接。服务器正在运行一个 tcp 监听器。
代码如下:客户:
package server
import (
"errors"
"log"
"net"
)
var tcpPool chan net.Conn
func NewClient(connections int, address string) {
tcpPool = make(chan net.Conn, connections)
for i := 0; i < connections; i++ {
conn, err := net.Dial("tcp4", address)
if err != nil {
log.Panic(err)
}
tcpPool <- conn
}
}
func SendMessage(msg []byte) ([]byte, error) {
conn := getConn()
log.Println("check conn: ", conn)
log.Println("msg: ", msg)
defer releaseConn(conn)
// send message
n, err := conn.Write(msg)
if err != nil {
log.Panic(err)
} else if n < len(msg) {
log.Panic(errors.New("Message did not send in full"))
}
// receiving a message
inBytes := make([]byte, 0)
for {
// bufsize 1024, read bufsize bytes each time
b := make([]byte, bufSize)
res, err := conn.Read(b)
log.Println("server sends >>>>>>>>>>>>: ", res)
if err != nil {
b[0] = ReError
break
}
inBytes = append(inBytes, b[:res]...)
// message finished.
if res < bufSize {
break
}
}
// check replied message
if len(inBytes) == 0 {
return []byte{}, errors.New("empty buffer error")
}
log.Println("SendMessage gets: ", inBytes)
return inBytes, nil
}
func releaseConn(conn net.Conn) error {
log.Println("return conn to pool")
select {
case tcpPool <- conn:
return nil
}
}
func getConn() (conn net.Conn) {
log.Println("Take one from pool")
select {
case conn := <-tcpPool:
return conn
}
}
服务器
func StartTCPServer(network, addr string) error {
listener, err := net.Listen(network, addr)
if err != nil {
return errors.Wrapf(err, "Unable to listen on address %s\n", addr)
}
log.Println("Listen on", listener.Addr().String())
defer listener.Close()
for {
log.Println("Accept a connection request.")
conn, err := listener.Accept()
if err != nil {
log.Println("Failed accepting a connection request:", err)
continue
}
log.Println("Handle incoming messages.")
go onConn(conn)
}
}
//onConn recieves a tcp connection and waiting for incoming messages
func onConn(conn net.Conn) {
inBytes := make([]byte, 0)
defer func() {
if e := recover(); e != nil {
//later log
if err, ok := e.(error); ok {
println("recover", err.Error())
}
}
conn.Close()
}()
// load msg
for {
buf := make([]byte, bufSize)
res, err := conn.Read(buf)
log.Println("server reading: ", res)
inBytes = append(inBytes, buf[:res]...)
if err != nil || res < bufSize {
break
}
}
var req RPCRequest
err := json.Unmarshal(inBytes, &req)
if err != nil {
log.Panic(err)
}
log.Println("rpc request: ", req)
var query UserRequest
err = json.Unmarshal(req.Query, &query)
if err != nil {
log.Panic(err)
}
log.Println("rpc request query: ", query)
// call method to process request
// good now we can proceed to function call
// some actual function calls gets a output
// outBytes, err := json.Marshal(out)
conn.Write(outBytes)
}
我认为这是非常标准的。但由于某种原因,我只能在客户端发送消息,然后第二个和第三个开始显示一些不正常。
1st ---> 成功,得到响应第二 ---> 客户端可以发送但没有返回,服务器端的日志显示没有消息第 3 次 ---> 如果我再次从客户端发送,它显示 broken pipe
错误..
最佳答案
有一些不好的处理方式。首先,确保来自服务器的消息完成的标志取决于 io.EOF,而不是长度
// message finished.
if res < 512 {
break
}
取而代之的是,读取器返回一个 io.EOF
是显示消息完成的唯一符号。其次,chan type
有阻塞的属性,不需要使用select。顺便说一下,你真的需要启动一个goroutine来释放。同样要求getConn
func releaseConn(conn net.Conn) {
go func(){
tcpPool <- conn
}()
}
func getConn() net.Conn {
con := <-tcpPool
return con
}
第三,listener不要关闭,下面的代码不好
defer listener.Close()
最重要的原因是在客户端,res, err := conn.Read(b)
这会收到服务器的回复。当没有回复时,它会阻止而不是 io.EOF,也不会出现其他错误。这意味着,您不能将持久通信部分装入函数 send() 中。您可以做一件事来使用 sendmsg() 发送,但永远不要使用 sendmsg() 来处理回复。你可以这样处理回复
var receive chan string
func init() {
receive = make(chan string, 10)
}
func ReceiveMessage(con net.Conn) {
// receiving a message
inBytes := make([]byte, 0, 1000)
var b = make([]byte, 512)
for {
// bufsize 1024, read bufsize bytes each time
res, err := con.Read(b)
if err != nil {
if err == io.EOF {
break
}
fmt.Println(err.Error())
break
}
inBytes = append(inBytes, b[:res]...)
msg := string(inBytes)
fmt.Println("receive msg from server:" + msg)
receive <- msg
}
}
我在你的代码中发现了几个问题,但我不知道是哪一个导致了你的失败。这是我根据您编写的代码并进行了一些修复。客户端.go:
package main
import (
"fmt"
"io"
"log"
"net"
)
var tcpPool chan net.Conn
var receive chan string
func init() {
receive = make(chan string, 10)
}
func NewClient(connections int, address string) {
tcpPool = make(chan net.Conn, connections)
for i := 0; i < connections; i++ {
conn, err := net.Dial("tcp", address)
if err != nil {
log.Panic(err)
}
tcpPool <- conn
}
}
func SendMessage(con net.Conn, msg []byte) error {
// send message
_, err := con.Write(msg)
if err != nil {
log.Panic(err)
}
return nil
}
func ReceiveMessage(con net.Conn) {
// receiving a message
inBytes := make([]byte, 0, 1000)
var b = make([]byte, 512)
for {
// bufsize 1024, read bufsize bytes each time
res, err := con.Read(b)
if err != nil {
if err == io.EOF {
break
}
fmt.Println(err.Error())
break
}
inBytes = append(inBytes, b[:res]...)
msg := string(inBytes)
fmt.Println("receive msg from server:" + msg)
receive <- msg
}
}
func getConn() net.Conn {
con := <-tcpPool
return con
}
func main() {
NewClient(20, "localhost:8101")
con := <-tcpPool
e := SendMessage(con, []byte("hello, i am client"))
if e != nil {
fmt.Println(e.Error())
return
}
go ReceiveMessage(con)
var msg string
for {
select {
case msg = <-receive:
fmt.Println(msg)
}
}
}
server.go
package main
import (
"fmt"
"io"
"net"
)
func StartTCPServer(network, addr string) error {
listener, err := net.Listen(network, addr)
if err != nil {
return err
}
for {
conn, err := listener.Accept()
if err != nil {
fmt.Println(err.Error())
continue
}
onConn(conn)
}
}
//onConn recieves a tcp connection and waiting for incoming messages
func onConn(conn net.Conn) {
inBytes := make([]byte, 0)
// load msg
for {
buf := make([]byte, 512)
res, err := conn.Read(buf)
if err != nil {
if err == io.EOF {
return
}
fmt.Println(err.Error())
return
}
inBytes = append(inBytes, buf[:res]...)
fmt.Println("receive from client:" + string(inBytes))
conn.Write([]byte("hello"))
}
}
func main() {
if e := StartTCPServer("tcp", ":8101"); e != nil {
fmt.Println(e.Error())
return
}
}
这有效,没有错误。顺便说一句,我看不到您在客户端或服务器端的哪个位置执行 con.Close()。关闭它是必要的。这意味着连接一旦从池中获取,就不会再放回去。当你认为一个连接结束时,关闭它并建立一个新的连接来填充池而不是把它放回去,因为把一个关闭的连接放回池中是一个致命的操作。
关于go - 多次使用TCP连接返回 'broken pipe'错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54454187/
我正在处理一个巨大的 xml 文档(其中包含大约一百万个条目),然后使用 rabbitmq 将格式化版本导入数据库。每次发布大约 200,000 个条目后,我都会收到一个 broken pipe 错误
2022-06-27 10:01:17.501 ERROR 1 --- [nio-5010-exec-7] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Ser
当我在删除软件包时看到奇怪的行为时,我有点像 linux 新手并且一直在设置我的系统。 即,当我尝试使用 Synaptic 删除新安装的软件包时,它有时会提示该软件包已损坏并且我无法完成我的任务。第二
为什么我会收到“xyz 上的内部链接损坏”,其中 xyz 不是托管网站的服务器的 IP 地址? 更具体地说:我的网站地址是“myExample.com”,还有另一个 IP 地址,我们称之为“anoth
我正在用 Java 编写一个简单的服务器,并且我能够在服务器端检索来自客户端的传入数据,但由于 2000 毫秒的超时而无法在客户端检索传入数据。有谁知道为什么会超时? 这是服务器的代码: privat
使用此 HTML 和 CSS: code { background-color: grey; padding: 2px 7px; line-height: 24px; /* this do
这是一个页面,如果设备无法连接,我将尝试从文件系统加载备份 var
为什么该模式被认为已损坏?我觉得还好吗?有什么想法吗? public static Singleton getInst() { if (instace == null) createInst(
根据documentation : Once an iterator’s __next__() method raises StopIteration, it must continue to do
可能是一个业余爱好者的标志,我想知道问题是不是公案(而不是我),但是,考虑一下这个公案 def test_calling_global_methods_without_parentheses
我正在使用 chrome://inspect/#devices通过cordova检查我的android-app构建的WebView。它在我的 Mac 上运行模拟器。可以找到该设备,但如果我在 WebV
我有一个 headless Ubuntu 服务器。我从 Mac 上通过 SSH 在服务器上运行命令(snapraid 同步)。指挥说大约需要6个小时,所以我就留了一夜。 当我今天早上下来时,Mac 上
我正在实现与 Android 应用程序通信的服务器端应用程序。安卓应用程序之前已经实现了原来与C++ Server的通信。现在我想用java代码替换C++服务器。 Android 应用程序与服务器通信
已关闭。这个问题是 not reproducible or was caused by typos 。目前不接受答案。 这个问题是由拼写错误或无法再重现的问题引起的。虽然类似的问题可能是 on-top
我对 2D 引擎的世界还很陌生。我弄清楚了如何加载图像并将其显示为 Sprite 和其他东西,但有一个问题困扰着我。例如,当“火箭”击中一个物体时,它会对其造成伤害并留下一个弹坑。我想在那个物体上显示
我无法使用 IF 语句来执行“正确”的操作,即代码; public function getUID($email) { $query = $this->dbh->prepare("SELECT
我认为这是一个非常简单的设置,但不知何故我遗漏了一些东西...... 这是传出的 HTML。这是一个简单的固定宽度 2 列布局: ... ... ... ...
我在使此布局在 IE 中正常工作时遇到了一些问题。问题是,当我有一些小型大写字母、带下划线的文本时,将垂直对齐设置为中间的图像会打断下划线。小写字母的下划线向下移动。 See the picture.
我正在使用 YUI 来重置浏览器类,然后我带来了 在几个自定义样式表中...我已经看到这种情况发生了几次,但我认为我从未缩小过原因范围: 表格正在拉入图像以组成带阴影的方形表格...但由于某种原因,它
在这个片段中我有两个部分。 第一个显示两列(使用 display: flex;)和一个列上方的标题。我必须使用一个中间标签(在本例中为文章)将“flex”保持在原位。 但我想知道是否有一个 CSS 属
我是一名优秀的程序员,十分优秀!