How to test TCP disconnection in GO

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

How to test TCP disconnection in GO

问题

我确实有一个从第二个本地进程接收数据的过程。我需要测试连接错误是否处理得当,并且在断开连接后是否自动重新连接并继续接收数据。

为了做到这一点,我正在尝试使其突然断开连接,或者将TCP连接置于错误状态,以进行单元测试。
此问题所示,要检查连接是否关闭,我正在检查数据是否到达,并测试是否返回错误。
我不确定如何:

  • 不正常地关闭连接
  • 使其处于错误状态

这是我的数据接收器的核心代码:

import (
	"bufio"
	"encoding/json"
	"fmt"
	"io"
	"net"
)

type Message struct {
	ID string `json:"id"`
}

func ReceiveData(listener Listener) {
	var tcpConn net.Conn
	var addr string = "127.0.0.1:9999"
	tcpConn, err := net.Dial("tcp", addr)
	socketReader := bufio.NewReader(tcpConn)
	decoder := json.NewDecoder(socketReader)

	for {
		var msg Message
		if err := decoder.Decode(&msg); err == io.EOF {
			listener.ProcessUpdate(Message{}, fmt.Errorf("Received EOF"), nil)
			tcpConn = nil
			return
		} else if err != nil {
			listener.ProcessUpdate(Message{}, nil, fmt.Errorf("Error decoding message: %s", err.Error()))
			tcpConn = nil
			return
		}

		// 处理消息
		_ = msg

		// 测试断开连接
		// 这不会断开连接:
		// tcpConn = nil
		// 这样做会正常断开连接:
		// tcpConn.Close()
	}
}

我没有模拟TCP连接,因为我想尝试使用真实的数据生成器。如果需要,我会研究一下。

英文:

I do have a process receiving data from second local process. I need to test if connection errors are handled well AND if it automatically reconnects and keep receiving data after a disconnection.

To do so I am trying to make it disconnect abruptly or put the TCP connection in an error state from a unit test.
As seen in this question to check if a connection is closed I am checking for data to come and test if it returns an error.
I am not sure how to:

  • close the connection ungracefully
  • make it be in an error state

This is the essence of my data receiver:

    import (
    	"bufio"
    	"encoding/json"
    	"fmt"
    	"io"
    	"net"
    )
    
    type Message struct {
    	ID string `json:"id"`
    }
    
    func ReceiveData(listener Listener) {
    	var tcpConn net.Conn
    	var addr string = "127.0.0.1:9999"
    	tcpConn, err := net.Dial("tcp", addr)
    	socketReader := bufio.NewReader(tcpConn)
    	decoder := json.NewDecoder(socketReader)
    
    	for {
			var msg Message
			if err := decoder.Decode(&msg); err == io.EOF {
				listener.ProcessUpdate(Message{}, fmt.Errorf("Received EOF"), nil)
				tcpConn = nil
				return
			} else if err != nil {
				listener.ProcessUpdate(Message{}, nil, fmt.Errorf("Error decoding message: %s", err.Error()))
				tcpConn = nil
				return
		}

		// process message
		_ = msg

		// Test disconnection
		// This does not disconnect:
		// tcpConn = nil
		// This does but gracefully:
		// tcpConn.Close()
	}

I am not mocking the TCP connection as I'd like to try with the real data producer. If is needed I'll look at it.

答案1

得分: 2

一种解决方法是为TCP连接本身设置一个截止时间:

tcpConn.SetDeadline(time.Now())

稍后,这将触发一个超时错误,可以通过以下方式捕获:

err := decoder.Decode(&msg)
if err != nil {
    if neterr, ok := err.(net.Error); ok && neterr.Timeout() {
        fmt.Errorf("TCP超时:%s", err.Error())
    } else {
        fmt.Errorf("接收消息解码错误:%s", err.Error())
    }
}
英文:

A solution is to set a deadline to the TCP connection itself:

tcpConn.SetDeadline(time.Now())

Later this will trigger a timeout error which can be caught with:

err := decoder.Decode(&msg);
if err != nil {
    if neterr, ok := err.(net.Error); ok && neterr.Timeout() {
		fmt.Errorf("TCP timeout : %s", err.Error())
	} else {
		fmt.Errorf("Received error decoding message: %s", err.Error())
	}
}

huangapple
  • 本文由 发表于 2016年11月29日 17:28:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/40862157.html
匿名

发表评论

匿名网友

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

确定