在Go语言中,在EOF时重新连接TCP。

huangapple go评论84阅读模式
英文:

Reconnect TCP on EOF in Go

问题

我有以下代码:

    //在init函数中
    if logStashHost != "" {
		lsconn, err = net.Dial("tcp", logStashHost)
	}
    ...
    ToLogStash(rec, lsconn)

然后有两个函数:

func ReadLogStash(conn net.Conn) {
	buffer := make([]byte, 256)
	for {
		_, err := conn.Read(buffer)
		if err != nil {
			fmt.Println(err)
		} else {
			fmt.Println(buffer)
		}
	}
}

func ToLogStash(r *logrow.Record, conn net.Conn) {
	b, err := json.Marshal(r)
	if err != nil {
		fmt.Println(err)
		return
	}
	_, err = fmt.Fprintln(conn, string(b))
	if err != nil {
		fmt.Println(err)
	}
}

其中ReadLogStash是一个正在运行的goroutine。如果另一端关闭,我会收到EOF。在ReadLogStash中,如何实现在收到EOF时每隔X秒尝试重新建立连接的好方法?

英文:

I have the following:

    //In an init func
    if logStashHost != "" {
		lsconn, err = net.Dial("tcp", logStashHost)
	}
    ...
    ToLogStash(rec, lsconn)

Then Two functions:

func ReadLogStash(conn net.Conn) {
	buffer := make([]byte, 256)
	for {
		_, err := conn.Read(buffer)
		if err != nil {
			fmt.Println(err)
		} else {
			fmt.Println(buffer)
		}
	}
}

func ToLogStash(r *logrow.Record, conn net.Conn) {
	b, err := json.Marshal(r)
	if err != nil {
		fmt.Println(err)
		return
	}
	_, err = fmt.Fprintln(conn, string(b))
	if err != nil {
		fmt.Println(err)
	}
}

Where ReadLogStash is a running goroutine. If the other side closes, I get EOF. What would be a good implementation in ReadLogStash to have it attempt to reestablish the connection every X seconds when it gets an EOF?

答案1

得分: 8

Go语言中有用于同步和通信的通道,你可以使用它们!

在一个循环中建立连接,并等待某种消息通过通道返回。

errCh := make(chan error)
for {
    lsconn, err = net.Dial("tcp", logStashHost)
    // 检查错误!
    go ReadLogStash(lsconn, errCh)
    err = <-errCh
    if err != nil {
        // 错误处理
        break
    }
    // 休眠以进行重试?
}
func ReadLogStash(conn net.Conn, errCh chan error) {
    _, err := io.Copy(os.Stderr, conn)
    if err != nil {
        fmt.Println(err)
    }
    // 从io.Copy返回的nil错误表示已达到文件末尾(EOF)。
    errCh <- err
}

除非在ReadLogStash函数中还有其他功能,否则你可能只需在内联中使用io.Copy,并忽略整个函数,但这种模式可能对你仍然有用。

英文:

Go has channels for synchronization and communication, use them!

Make your connection in a loop, and have it wait for some sort of message to come back on a channel.

...
errCh := make(chan error)
for {
	lsconn, err = net.Dial(&quot;tcp&quot;, logStashHost)
	// check error!
	go ReadLogStash(lsconn, errCh)
	err = &lt;-errCh
	if err != nil {
		// bad error
		break
	}
	// sleep to backoff on retries?
}
...

func ReadLogStash(conn net.Conn, errCh chan error) {
	_, err := io.Copy(os.Stderr, conn)
	if err != nil {
		fmt.Println(err)
	}
	// a nil error from io.Copy means you reached EOF.
	errCh &lt;- err
}

Unless you have more functionality in ReadLogStash, you can probably just use io.Copy inline, and forget the entire function, but this pattern may come in useful for you anyway.

答案2

得分: 1

这是我最终采用的代码,使用了一个通道(channel)是正确的方向:

if logStashHost != "" {
    lsc = make(chan *logrow.Record)
    go ToLogStash(lsc, logStashHost)
}
...
if lsc != nil {
    lsc <- rec
}
...
func ToLogStash(c chan *logrow.Record, logStashHost string) {
    var lsconn net.Conn
    var enc *json.Encoder
    var err error
    connect := func() {
        for {
            lsconn, err = net.Dial("tcp", logStashHost)
            if err == nil {
                enc = json.NewEncoder(lsconn)
                break
            }
            log.Println(err)
            time.Sleep(time.Second)
        }
    }
    connect()
    for r := range c {
        err = enc.Encode(r)
        if err != nil {
            lsconn.Close()
            log.Println(err)
            connect()
        }
    }
}

以上是要翻译的内容。

英文:

Here is what I ended up going with, a channel was the right direction:

if logStashHost != &quot;&quot; {
	lsc = make(chan *logrow.Record)
	go ToLogStash(lsc, logStashHost)
}
...
if lsc != nil {
   lsc &lt;- rec
}
...
func ToLogStash(c chan *logrow.Record, logStashHost string) {
	var lsconn net.Conn
	var enc *json.Encoder
	var err error
	connect := func() {
		for {
			lsconn, err = net.Dial(&quot;tcp&quot;, logStashHost)
			if err == nil {
				enc = json.NewEncoder(lsconn)
				break
			}
			log.Println(err)
			time.Sleep(time.Second)
		}
	}
	connect()
	for r := range c {
		err = enc.Encode(r)
		if err != nil {
			lsconn.Close()
			log.Println(err)
			connect()
		}
	}
}

huangapple
  • 本文由 发表于 2014年5月1日 02:31:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/23395519.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定