ROS-I simple_message 源码分析:SmplMsgConnection

SmplMsgConnection类定义了一些接口和常用的方法,用于SimpleMessage消息的发送,它做了两个假设:

  • 连接能够发送原始字节数据(封装在simple message之中)
  • 提供显示的connect方法来建立连接(相应的也要有一个disconnect),对于无连接的通信,比如UDP,则可以不用实现connect方法(作为一个空操作)

此处的连接(connection)是代表的抽象连接,也就是说,可以是TCP、UDP、串口等各种通信连接方式,而这一层是不关心具体的通信类型的。

namespace industrial
{
namespace smpl_msg_connection
{

class SmplMsgConnection

{
public:

  virtual bool sendMsg(industrial::simple_message::SimpleMessage & message);
  virtual bool receiveMsg(industrial::simple_message::SimpleMessage & message);
  bool sendAndReceiveMsg(industrial::simple_message::SimpleMessage & send,
                         industrial::simple_message::SimpleMessage & recv, 
                         bool verbose = false);

  virtual bool isConnected()=0;
  virtual bool makeConnect()=0;

private:

  virtual bool sendBytes(industrial::byte_array::ByteArray & buffer) =0;
  virtual bool receiveBytes(industrial::byte_array::ByteArray & buffer,
                            industrial::shared_types::shared_int num_bytes) =0;

};

} //namespace message_connection
} //namespace industrial
纯虚函数

可以看到,继承的用户类需要实现的方法有四个:makeConnectisConnectedsendBytesreceiveBytes。而高一层的发送和接收SimpleMessage消息已经在基类中实现。

  • makeConnect
    连接远程主机
  • isConnected
    返回是否处于连接状态
  • sendBytes
    发送字节数据,sendMsg会调用这个方法
  • receiveBytes
    同步接收字节数据,receiveMsg会调用这个方法

当子类实现这4个方法后,就可以直接欢乐的发送simple message了。我们来看一下发送和接收消息的代码:

发送simple message
bool SmplMsgConnection::sendMsg(SimpleMessage & message)
{
  bool rtn;
  ByteArray sendBuffer;
  ByteArray msgData;

  if (message.validateMessage())
  {
    message.toByteArray(msgData);
    sendBuffer.load((int)msgData.getBufferSize());
    sendBuffer.load(msgData);
    rtn = this->sendBytes(sendBuffer);
  }
  else
  {
    rtn = false;
    LOG_ERROR("Message validation failed, message not sent");
  }

return rtn;
}

传入的参数是SimpleMessage对象,通过toByteArray方法将message内部封装的ByteArray存储到临时变量msgData中,然后再调用两次load依次加载消息的长度(PREFIX)和内容(HEADER + BODY),最后调用sendBytes将封装好的完整消息发送出去。

接收simple message
bool SmplMsgConnection::receiveMsg(SimpleMessage & message)
{
  ByteArray lengthBuffer;
  ByteArray msgBuffer;
  int length;

  bool rtn = false;


  rtn = this->receiveBytes(lengthBuffer, message.getLengthSize());

  if (rtn)
  {
    rtn = lengthBuffer.unload(length);
    LOG_COMM("Message length: %d", length);

    if (rtn)
    {
      rtn = this->receiveBytes(msgBuffer, length);

      if (rtn)
      {
        rtn = message.init(msgBuffer);
      }
      else
      {
        LOG_ERROR("Failed to initialize message");
        rtn = false;
      }

    }
    else
    {
      LOG_ERROR("Failed to receive message");
      rtn = false;
    }
  }
  else
  {
    LOG_ERROR("Failed to receive message length");
    rtn = false;
  }

  return rtn;
}

receiveMsg是一个同步接收方法,首先执行receiveBytes(lengthBuffer, message.getLengthSize())获取当前消息的长度,再执行receiveBytes(msgBuffer, length)接收消息的具体内容,最后调用message.init(msgBuffer)初始化接收到的消息,也就是根据协议对原始字节进行解包,填充到message中的各个成员中。

发送并接收simple message
bool SmplMsgConnection::sendAndReceiveMsg(SimpleMessage & send, SimpleMessage & recv, bool verbose)
{   
  bool rtn = false;
  rtn = this->sendMsg(send);
  if (rtn)
  {
    if(verbose) {
      LOG_ERROR("Sent message");
    }
    rtn = this->receiveMsg(recv);
    if(verbose) {
      LOG_ERROR("Got message");
    }
  }
  else
  {
    rtn = false;
  }

  return rtn;
}

比较简单,依次调用sendMsg和receiveMsg即可完成一次发送并接收操作。

你可能感兴趣的:(ROS-I simple_message 源码分析:SmplMsgConnection)