Skip to content

github.com/simonvetter/modbus tcp_transport.go源码分析

函数:newTCPTransport

1func newTCPTransport(socket net.Conn, timeout time.Duration, customLogger *log.Logger) (tt *tcpTransport) {
2	tt = &tcpTransport{
3		socket:		socket,
4		timeout:	timeout,
5		logger:		newLogger(fmt.Sprintf("tcp-transport(%s)", socket.RemoteAddr()), customLogger),
6	}
7	return
8}
  1. 这是一个构造函数,用于创建新的 tcpTransport 实例。
  2. 将给定的 sockettimeout 分配给新实例的相应字段。
  3. 使用 newLogger 函数创建一个新的日志记录器,其中日志的前缀包含 TCP 套接字的远程地址。
  4. 返回新创建的 tcpTransport 实例。

函数:Close

1func (tt *tcpTransport) Close() (err error) {
2	err  = tt.socket.Close()
3	return
4}
  1. 这个方法尝试关闭 tcpTransport 的 TCP 套接字。
  2. 返回关闭操作的结果,即错误 err(如果有)。

函数:ExecuteRequest

 1func (tt *tcpTransport) ExecuteRequest(req *pdu) (res *pdu, err error) {
 2	err	= tt.socket.SetDeadline(time.Now().Add(tt.timeout))
 3	if err != nil {
 4		return
 5	}
 6	tt.lastTxnId++
 7	_, err	= tt.socket.Write(tt.assembleMBAPFrame(tt.lastTxnId, req))
 8	if err != nil {
 9		return
10	}
11	res, err = tt.readResponse()
12	return
13}
  1. 设置套接字的 I/O 截止时间,确保读/写操作在指定的超时时限内完成。
  2. 递增事务 ID(tt.lastTxnId)。
  3. 使用 assembleMBAPFrame 方法将给定的 PDU req 转换为一个 MBAP 帧,然后写入 TCP 套接字。
  4. 使用 readResponse 方法从套接字中读取响应。
  5. 返回读取到的响应和任何遇到的错误。

函数:ReadRequest

 1func (tt *tcpTransport) ReadRequest() (req *pdu, err error) {
 2	err	= tt.socket.SetDeadline(time.Now().Add(tt.timeout))
 3	if err != nil {
 4		return
 5	}
 6	req, _, err	= tt.readMBAPFrame()
 7	if err != nil {
 8		return
 9	}
10	tt.lastTxnId = txnId
11	return
12}
  1. 设置套接字的 I/O 截止时间。
  2. 使用 readMBAPFrame 从套接字读取一个 MBAP 帧。
  3. 将读取的事务 ID 存储在 tt.lastTxnId 中。
  4. 返回读取的请求和任何遇到的错误。

函数:WriteResponse

1func (tt *tcpTransport) WriteResponse(res *pdu) (err error) {
2	_, err	= tt.socket.Write(tt.assembleMBAPFrame(tt.lastTxnId, res))
3	return
4}
  1. 使用 assembleMBAPFrame 方法将给定的 PDU res 转换为一个 MBAP 帧。
  2. 将这个帧写入 TCP 套接字。
  3. 返回任何遇到的错误。

函数:readResponse

 1func (tt *tcpTransport) readResponse() (res *pdu, err error) {
 2	for {
 3		res, txnId, err = tt.readMBAPFrame()
 4		if err == ErrUnknownProtocolId {
 5			continue
 6		}
 7		if err != nil {
 8			return
 9		}
10		if tt.lastTxnId != txnId {
11			tt.logger.Warningf("received unexpected transaction id (expected 0x%04x, received 0x%04x)", tt.lastTxnId, txnId)
12			continue
13		}
14		break
15	}
16	return
17}
  1. 在一个无限循环中读取 MBAP 帧,直到找到一个与 tt.lastTxnId 匹配的事务 ID。
  2. 如果遇到未知的协议 ID 错误,继续循环并尝试读取下一个帧。
  3. 如果遇到其他错误,返回错误。
  4. 如果接收到的事务 ID 与预期的事务 ID 不匹配,记录一个警告并

继续循环。 5. 如果找到匹配的事务 ID,跳出循环并返回响应。

Related Posts

  1. github.com/simonvetter/modbus client.go源码分析
  2. github.com/simonvetter/modbus rtu_transport.go源码分析
  3. github.com/simonvetter/modbus server.go源码分析