diff --git a/README.md b/README.md index e952636..e1e4af4 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,13 @@ go modbus [![Build Status](https://travis-ci.org/goburrow/modbus.svg?branch=master)](https://travis-ci.org/goburrow/modbus) [![GoDoc](https://godoc.org/github.com/goburrow/modbus?status.svg)](https://godoc.org/github.com/goburrow/modbus) ========= -Fault-tolerant, fail-fast implementation of Modbus protocol in Go. +This is a fork of https://github.com/gburrow/modbus (possibly abandoned), +a Fault-tolerant, fail-fast implementation of Modbus protocol in Go. + +Bug fixes +------------------- +* Add a read buffer flush for tcp clients just prior to launching the next call. This + resolves transaction ID mismatches that cause the connection to never work + again. Supported functions ------------------- diff --git a/tcpclient.go b/tcpclient.go index 4e53c73..5cbd532 100644 --- a/tcpclient.go +++ b/tcpclient.go @@ -156,6 +156,18 @@ func (mb *tcpTransporter) Send(aduRequest []byte) (aduResponse []byte, err error // Set timer to close when idle mb.lastActivity = time.Now() mb.startCloseTimer() + + /* + * If an answer to a previously timed-out request is already in teh buffer, this will result + * in a transaction ID mismatch from which we will never recover. To prevent this, just + * flush any previous reponses before launching the next poll. That's throwing away + * possibly useful data, but the previous request was already satisfied with a timeout + * error so that probably makes the most sense here. + * + * Be aware that this call resets the read deadline. + */ + mb.flushAll() + // Set write and read timeout var timeout time.Time if mb.Timeout > 0 { @@ -252,6 +264,31 @@ func (mb *tcpTransporter) flush(b []byte) (err error) { return } +/** + * This function implements a non-blocking read flush. Be warned it resets + * the read deadline. + */ +func (mb *tcpTransporter) flushAll() (int, error) { + if err := mb.conn.SetReadDeadline(time.Now()); err != nil { + return 0, err + } + + count := 0 + buffer := make([]byte, 1024) + + for { + n, err := mb.conn.Read(buffer) + + if err != nil { + return count + n, err + } else if n > 0 { + count = count + n + } else { + /* didn't flush any new bytes, return */ + return count, err + } + } +} func (mb *tcpTransporter) logf(format string, v ...interface{}) { if mb.Logger != nil { mb.Logger.Printf(format, v...)