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
纯虚函数
可以看到,继承的用户类需要实现的方法有四个:makeConnect,isConnected,sendBytes,receiveBytes。而高一层的发送和接收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即可完成一次发送并接收操作。