udp

UDT是建立在UDP协议基础之上的应用层协议,其最终是通过UDP协议来接发数据。

udt包结构解释

最近在看udt协议的一些知识,先把包结构放上来

UDT包结构

 

总体结构:

0               1               2               3               

0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 

Packet Header(包头)

Data/Control Information Field(数据包/控制包 信息)

 

数据包包头结构:

0               1               2               3               

0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 

0 |                           Sequence Number

ff  |o |                       Message Number

                             Time Stamp

                             Destination Socket ID

 

bit 0:

0: Data Packet(0:数据包)

1: Control Packet(1:控制包)

bit ff:

11: solo message packet(11:单一的消息包)

10: first packet of a message(10:一份消息的第一个包)

01: last packet of a message(00:一份消息的最后一个包)

bit o:

0: in order delivery not required(0:没有要求按正常序号传递)

1: in order delivery required(1:要求按正常序号传递)

 

控制包包头结构:

0               1               2               3               

0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 

1 |       Type             |       Reserved

Additional Info

                             Time Stamp

                             Destination Socket ID

bit 0:

0: Data Packet(0:数据包)

1: Control Packet(1:控制包)

bit 1~15:

       0: Protocol Connection Handshake

Add. Info:    Undefined

Control Info: Handshake information (see CHandShake)

1: Keep-alive

Add. Info:    Undefined

Control Info: None

2: Acknowledgement (ACK)

Add. Info:    The ACK sequence number

Control Info: The sequence number to which (but not include) all the previous packets have beed received

Optional:     RTT

RTT Variance

advertised flow window size (number of packets)

estimated bandwidth (number of packets per second)

3: Negative Acknowledgement (NAK)

Add. Info:    Undefined

Control Info: Loss list (see loss list coding below)

4: Congestion Warning

Add. Info:    Undefined

Control Info: None

5: Shutdown

Add. Info:    Undefined

Control Info: None

6: Acknowledgement of Acknowledement (ACK-square)

Add. Info:    The ACK sequence number

Control Info: None

7: Message Drop Request

Add. Info:    Message ID

Control Info: first sequence number of the message

last seqeunce number of the message

     65535: Explained by bits 16 - 31

 

bit 16 - 31:

This space is used for future expansion or user defined control packets.

在UDT的实现中,是通过类CChannel来处理的,顾名思义,可以理解为通过UDP管道来接发数据。

       来看看CChannel提供的主要方法:

void setSndBufSize(const int& size);

void setRcvBufSize(const int& size);

void open(const sockaddr* addr = NULL);

int sendto(const sockaddr* addr, CPacket& packet) const;

int recvfrom(sockaddr* addr, CPacket& packet) const;

注:CPacket即UDP包结构(数据包与控制包)

 

#ifndef WIN32

  int m_iSocket;                    // socket descriptor

#else

  SOCKET m_iSocket;

#endif

int m_iSndBufSize;                   // UDP sending buffer size

int m_iRcvBufSize;                   // UDP receiving buffer size

 

setSndBufSize与setRcvBufSize分别设置发送和接收缓冲区大小,即对m_iSndBufSize和m_iRcvBufSize赋值,主要看看open函数:

void CChannel::open(const sockaddr* addr)

{

   // construct an socket

   m_iSocket = socket(m_iIPversion, SOCK_DGRAM, 0);

   if (NULL != addr)

   {

      socklen_t namelen = (AF_INET == m_iIPversion) ? sizeof(sockaddr_in) :sizeof(sockaddr_in6);

      if (0 != bind(m_iSocket, addr, namelen))

         //error

   }

   else

   {

      //sendto or WSASendTo will also automatically bind the socket

      addrinfo hints;

      addrinfo* res;

      memset(&hints, 0, sizeof(struct addrinfo));

      hints.ai_flags = AI_PASSIVE;

      hints.ai_family = m_iIPversion;

      hints.ai_socktype = SOCK_DGRAM;

      if (0 != getaddrinfo(NULL, "0", &hints, &res))

        //error

      if (0 != bind(m_iSocket, res->ai_addr, res->ai_addrlen))

        //error

      freeaddrinfo(res);

   }

   setUDPSockOpt();    //调用TCP/IP协议栈提供的方法设置UDP选项(缓冲区大小)

}

void CChannel::setUDPSockOpt()

{

   if ((0 != setsockopt(m_iSocket, SOL_SOCKET, SO_RCVBUF, (char *)&m_iRcvBufSize, sizeof(int))) ||(0 != setsockopt(m_iSocket, SOL_SOCKET, SO_SNDBUF, (char *)&m_iSndBufSize,sizeof(int))))

      //error

 

   #ifdef WIN32

      DWORD ot = 1; //milliseconds

      if (setsockopt(m_iSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&ot, sizeof(DWORD)) < 0)

         throw CUDTException(1, 3, NET_ERROR);

   #else

      // Set receiving time-out value

      if (setsockopt(m_iSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(timeval)) < 0)

         throw CUDTException(1, 3, NET_ERROR);

   #endif

}

 

下面看看sendto函数,该函数是把CPacket内容通过udp发送出去,分linux系与win32两种情况。

int CChannel::sendto(const sockaddr* addr, CPacket& packet) const

{

   // 主机序到网络序

   if (packet.getFlag())//如果是控制包

      for (int i = 0, n = packet.getLength() / 4; i < n; ++ i)

         *((uint32_t *)packet.m_pcData + i) = htonl(*((uint32_t *)packet.m_pcData + i));

 

   // convert packet header into network order(包头序也需要转换)

   for (int j = 0; j < 4; ++ j)

      packet.m_nHeader[j] = htonl(packet.m_nHeader[j]);

 

   #ifndef WIN32

      msghdr mh;

      mh.msg_name = (sockaddr*)addr;

      mh.msg_namelen = (AF_INET == m_iIPversion) ? sizeof(sockaddr_in) : sizeof(sockaddr_in6);

      mh.msg_iov = (iovec*)packet.m_PacketVector;

      mh.msg_iovlen = 2;

      mh.msg_control = NULL;

      mh.msg_controllen = 0;

      mh.msg_flags = 0;

 

      int res = sendmsg(m_iSocket, &mh, 0);    //调用协议栈函数发送出去

   #else

      DWORD size = CPacket::m_iPktHdrSize + packet.getLength();

      int addrsize = (AF_INET == m_iIPversion) ? sizeof(sockaddr_in) : sizeof(sockaddr_in6);

      int res = WSASendTo(m_iSocket, (LPWSABUF)packet.m_PacketVector, 2, &size, 0, addr, addrsize, NULL, NULL);

      res = (0 == res) ? size : -1;

   #endif

 

   // 恢复序

   for (int k = 0; k < 4; ++ k)

      packet.m_nHeader[k] = ntohl(packet.m_nHeader[k]);

 

   if (packet.getFlag())

      for (int l = 0, n = packet.getLength() / 4; l < n; ++ l)

         *((uint32_t *)packet.m_pcData + l) = ntohl(*((uint32_t *)packet.m_pcData + l));

 

   return res;

}

 

recvfrom的原理也类似与sendto

int CChannel::recvfrom(sockaddr* addr, CPacket& packet) const

{

   #ifndef WIN32

      msghdr mh;   

      mh.msg_name = addr;

      mh.msg_namelen = (AF_INET == m_iIPversion) ? sizeof(sockaddr_in) : sizeof(sockaddr_in6);

      mh.msg_iov = packet.m_PacketVector;

      mh.msg_iovlen = 2;

      mh.msg_control = NULL;

      mh.msg_controllen = 0;

      mh.msg_flags = 0;

 

      #ifdef UNIX

         fd_set set;

         timeval tv;

         FD_ZERO(&set);

         FD_SET(m_iSocket, &set);

         tv.tv_sec = 0;

         tv.tv_usec = 10000;

         select(m_iSocket+1, &set, NULL, &set, &tv);

      #endif

 

      int res = recvmsg(m_iSocket, &mh, 0);

   #else

      DWORD size = CPacket::m_iPktHdrSize + packet.getLength();

      DWORD flag = 0;

      int addrsize = (AF_INET == m_iIPversion) ? sizeof(sockaddr_in) : sizeof(sockaddr_in6);

 

      int res = WSARecvFrom(m_iSocket, (LPWSABUF)packet.m_PacketVector, 2, &size, &flag, addr, &addrsize, NULL, NULL);

      res = (0 == res) ? size : -1;

   #endif

 

   if (res <= 0)

   {

      packet.setLength(-1);

      return -1;

   }

 

   packet.setLength(res - CPacket::m_iPktHdrSize);

 

   // convert back into local host order

   for (int i = 0; i < 4; ++ i)

      packet.m_nHeader[i] = ntohl(packet.m_nHeader[i]);

 

   if (packet.getFlag())

      for (int j = 0, n = packet.getLength() / 4; j < n; ++ j)

         *((uint32_t *)packet.m_pcData + j) = ntohl(*((uint32_t *)packet.m_pcData + j));

 

   return packet.getLength();

}

posted @ 2009-12-03 13:46  辛勤耕耘  阅读(723)  评论(0编辑  收藏  举报