UDT源码剖析(七)之Packet

CPacket

  • 基础数据结构
class CPacket
{
public:
   int32_t& m_iSeqNo;                   // 序列号
   int32_t& m_iMsgNo;                   // 信息号    
   int32_t& m_iTimeStamp;               // 更新RTT的Timestamp
   int32_t& m_iID;			// 目的地Socket ID
   char*& m_pcData;                     // 数据
   static const int m_iPktHdrSize;	// 头部信息(16字节)

protected:    //真正的数据信息
   uint32_t m_nHeader[4];               // 16字节的UDT头部
   iovec m_PacketVector[2];             // UDT头部数据和真实的数据信息

   int32_t __pad;
};
class CHandShake
{
public: 
   static const int m_iContentSize;	//握手包除了头部信息,有额外的48个字节

public:
   int32_t m_iVersion;          // UDT version
   int32_t m_iType;             // UDT socket type
   int32_t m_iISN;              // random initial sequence number
   int32_t m_iMSS;              // maximum segment size
   int32_t m_iFlightFlagSize;   // flow control window size
   int32_t m_iReqType;          // connection request type: 1: regular connection request, 0: rendezvous connection request, -1/-2: response
   int32_t m_iID;		// socket ID
   int32_t m_iCookie;		// cookie
   uint32_t m_piPeerIP[4];	// The IP address that the peer's UDP port is bound to
};
  • 初始化:CPacket::CPacket()
CPacket::CPacket():
m_iSeqNo((int32_t&)(m_nHeader[0])),    //将引用指向头部信息
m_iMsgNo((int32_t&)(m_nHeader[1])),
m_iTimeStamp((int32_t&)(m_nHeader[2])),
m_iID((int32_t&)(m_nHeader[3])),
m_pcData((char*&)(m_PacketVector[1].iov_base)),
__pad()
{
   for (int i = 0; i < 4; ++ i)    //将头部的信息初始化为0
      m_nHeader[i] = 0;
   m_PacketVector[0].iov_base = (char *)m_nHeader;    //初始化真实发送的数据结构
   m_PacketVector[0].iov_len = CPacket::m_iPktHdrSize;
   m_PacketVector[1].iov_base = NULL;
   m_PacketVector[1].iov_len = 0;
}
  • 获取与设置数据长度:void CPacket::setLength(int len)int CPacket::getLength() const
int CPacket::getLength() const
{
   return m_PacketVector[1].iov_len;
}

void CPacket::setLength(int len)
{
   m_PacketVector[1].iov_len = len;
}
  • 打包一个控制包:void CPacket::pack(int pkttype, void* lparam, void* rparam, int size)
void CPacket::pack(int pkttype, void* lparam, void* rparam, int size)
{
   // Set (bit-0 = 1) and (bit-1~15 = type)
   // 很明显是打包control packet
   m_nHeader[0] = 0x80000000 | (pkttype << 16);

   //根据提供的信息打包不同类型的控制包,不同控制包的头部信息是不同的,需要填充不同的数据
   switch (pkttype)
   {
   case 2: //0010 - Acknowledgement (ACK)
      if (NULL != lparam)   //如果时ACK,设置bit32~bit63为ACK序列号
         m_nHeader[1] = *(int32_t *)lparam;

      m_PacketVector[1].iov_base = (char *)rparam;    //设置ACK包中的数据选项
      m_PacketVector[1].iov_len = size;

      break;

   case 6: //0110 - Acknowledgement of Acknowledgement (ACK-2)
      m_nHeader[1] = *(int32_t *)lparam;    //在bit32~bit63填充ACK序列号

      //应答ACK包,除了报头没有额外的信息,但是需要填充  
      m_PacketVector[1].iov_base = (char *)&__pad; //NULL;
      m_PacketVector[1].iov_len = 4; //0;

      break;

   case 3: //0011 - Loss Report (NAK)
      // loss list
      m_PacketVector[1].iov_base = (char *)rparam;  //在数据区域填充丢失的list信息
      m_PacketVector[1].iov_len = size;

      break;

   case 4: //0100 - Congestion Warning
      // control info field should be none
      // but "writev" does not allow this
      m_PacketVector[1].iov_base = (char *)&__pad; //拥塞警告;
      m_PacketVector[1].iov_len = 4; //0;
  
      break;

   case 1: //0001 - Keep-alive
      // control info field should be none
      // but "writev" does not allow this
      m_PacketVector[1].iov_base = (char *)&__pad; //生存报文
      m_PacketVector[1].iov_len = 4; //0;

      break;

   case 0: //0000 - Handshake
      // control info filed is handshake info
      m_PacketVector[1].iov_base = (char *)rparam;  //握手报文,在数据区域填充CHandShake
      m_PacketVector[1].iov_len = size; //sizeof(CHandShake);

      break;

   case 5: //0101 - Shutdown
      // control info field should be none
      // but "writev" does not allow this
      m_PacketVector[1].iov_base = (char *)&__pad; //连接终止报文
      m_PacketVector[1].iov_len = 4; //0;

      break;

   case 7: //0111 - Message Drop Request
      // msg id 
      m_nHeader[1] = *(int32_t *)lparam;    //消息丢弃请求.需要丢弃的消息ID

      //first seq no, last seq no
      m_PacketVector[1].iov_base = (char *)rparam;    //在数据区域填充需要丢弃的报文
      m_PacketVector[1].iov_len = size;

      break;

   case 8: //1000 - Error Signal from the Peer Side
      // Error type
      m_nHeader[1] = *(int32_t *)lparam;    //向对方发送警告信息报文,填充错误类型

      // control info field should be none
      // but "writev" does not allow this
      m_PacketVector[1].iov_base = (char *)&__pad; //NULL;
      m_PacketVector[1].iov_len = 4; //0;

      break;

   case 32767: //0x7FFF - Reserved for user defined control packets
      // for extended control packet
      // "lparam" contains the extended type information for bit 16 - 31
      // "rparam" is the control information
      m_nHeader[0] |= *(int32_t *)lparam;   //保留给用户实现

      if (NULL != rparam)
      {
         m_PacketVector[1].iov_base = (char *)rparam;
         m_PacketVector[1].iov_len = size;
      }
      else
      {
         m_PacketVector[1].iov_base = (char *)&__pad;
         m_PacketVector[1].iov_len = 4;
      }

      break;

   default:
      break;
   }
}
  • 获取包中的信息:int CPacket::getFlag() constint CPacket::getType() constint CPacket::getExtendedType() constint32_t CPacket::getAckSeqNo() const int CPacket::getMsgBoundary() constbool CPacket::getMsgOrderFlag() constint32_t CPacket::getMsgSeq() const
int CPacket::getFlag() const    //控制包返回1,数据包返回1
{
   // read bit 0
   return m_nHeader[0] >> 31;
}

int CPacket::getType() const    //获取控制包的具体类型:ACK,ACK-2,HandShake等
{
   // read bit 1~15
   return (m_nHeader[0] >> 16) & 0x00007FFF;
}

int CPacket::getExtendedType() const    //获取保留给用户实现的自定义类型
{
   // read bit 16~31
   return m_nHeader[0] & 0x0000FFFF;
}

int32_t CPacket::getAckSeqNo() const    //获取ACK序列号
{
   // read additional information field
   return m_nHeader[1];
}

int CPacket::getMsgBoundary() const    //判断数据流的位置,起始包,终止包或者独立包
{
   // read [1] bit 0~1
   return m_nHeader[1] >> 30;
}

bool CPacket::getMsgOrderFlag() const    //判断数据包是否需要立即提交给用户
{
   // read [1] bit 2
   return (1 == ((m_nHeader[1] >> 29) & 1));
}

int32_t CPacket::getMsgSeq() const    //获取MSG的编号
{
   // read [1] bit 3~31
   return m_nHeader[1] & 0x1FFFFFFF;
}

CHandShake

  • 获取握手包信息:int CHandShake::serialize(char* buf, int& size)
int CHandShake::serialize(char* buf, int& size)
{
   if (size < m_iContentSize)
      return -1;

   int32_t* p = (int32_t*)buf;
   *p++ = m_iVersion;
   *p++ = m_iType;
   *p++ = m_iISN;
   *p++ = m_iMSS;
   *p++ = m_iFlightFlagSize;
   *p++ = m_iReqType;
   *p++ = m_iID;
   *p++ = m_iCookie;
   for (int i = 0; i < 4; ++ i)
      *p++ = m_piPeerIP[i];

   size = m_iContentSize;

   return 0;
}
  • 填充握手包信息:int CHandShake::deserialize(const char* buf, int size)
int CHandShake::deserialize(const char* buf, int size)
{
   if (size < m_iContentSize)
      return -1;

   int32_t* p = (int32_t*)buf;
   m_iVersion = *p++;
   m_iType = *p++;
   m_iISN = *p++;
   m_iMSS = *p++;
   m_iFlightFlagSize = *p++;
   m_iReqType = *p++;
   m_iID = *p++;
   m_iCookie = *p++;
   for (int i = 0; i < 4; ++ i)
      m_piPeerIP[i] = *p++;

   return 0;
}

posted on 2018-06-16 18:29  ukernel  阅读(521)  评论(0编辑  收藏  举报

导航