Mqtt协议的实现,网上有很多文章、源码,可以下载来慢慢研究。比如《自己动手实现MQTT协议》,我参考的是这篇文章,按协议一点一点实现的。但对于离线消息的接收,所说的不多,一般的文章都是说到,要将ClearSession的标识设置为0,而用QoS要为1或者2,然后重新连接就可以收到离线消息了。
但在用C#实现的过程中,连接已经正常了,QoS也设置为2了,就是收不到离线的消息。后来发现,问题不是出现在协议上,而是在数据的接收上。在接收数据时,用socket.Receive来接收,在连接的时候,会返回数据,而接收的buff开的较大,则会在接收到服务端对connect回应的数据包外,也会把离线的数据也一起收起来。这时就要按协议来作解包处理了。如果没有作解包处理,则对收到的connect的conack命令处理,那后面的离线数据就会丢失了。
namespace MqttSDK
{
/// <summary>
/// Mqtt包的接收器
/// </summary>
public class MqttPacketReceiver
{
#region 属性
#region 固定头
/// <summary>
/// 包类型。占第一个字节的4-7bit
/// </summary>
public PacketTypeEnum PacketType { get; set; }
/// <summary>
/// 标识。占第一个字节的0-3bit
/// 包类型为PUBLISH时,对于MQTT 3.1.1,Bit 0:RETAIN3,Bit 1:QoS2,Bit 2:QoS2,Bit 3:DUP1。
/// 包类型为PUBREL、SUBSCRIBE、UNSUBSCRIBE时,Bit 1:1,Bit 0、Bit 2、Bit 3均为0。
/// 其他包类型,Bit 0、Bit 1、Bit 2、Bit 3均为0。
/// </summary>
public int Flags { get; set; }
/// <summary>
/// 剩余长度。可变头部和载荷的字节数之和。
/// </summary>
public int RemainingLength { get; set; }
public byte FirstByte { get; set; }
/// <summary>
/// 剩余长度对应的字节
/// </summary>
public List<byte> RemainingLengthBytes { get; set; }
#endregion
#region 可变头和载荷的数据
/// <summary>
/// 可变头和载荷的数据
/// </summary>
public List<byte> BytesOfVariableHeaderAndPayload { get; set; }
#endregion
#endregion
#region Read
/// <summary>
/// 从socket读取数据
/// </summary>
/// <param name="socket"></param>
public IMqttPacket Read(Socket socket)
{
if (socket == null)
{
return null;
}