UDT是建立在UDP協(xié)議基礎(chǔ)之上的應(yīng)用層協(xié)議,其最終是通過UDP協(xié)議來接發(fā)數(shù)據(jù)。
在UDT的實(shí)現(xiàn)中,是通過類CChannel來處理的,顧名思義,可以理解為通過UDP管道來接發(fā)數(shù)據(jù)。
來看看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包結(jié)構(gòu)(數(shù)據(jù)包與控制包)
#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分別設(shè)置發(fā)送和接收緩沖區(qū)大小,即對m_iSndBufSize和m_iRcvBufSize賦值,主要看看open函數(shù):
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(); //調(diào)用TCP/IP協(xié)議棧提供的方法設(shè)置UDP選項(xiàng)(緩沖區(qū)大?。?/span>
}
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函數(shù),該函數(shù)是把CPacket內(nèi)容通過udp發(fā)送出去,分linux系與win32兩種情況。
int CChannel::sendto(const sockaddr* addr, CPacket& packet) const
{
// 主機(jī)序到網(wǎng)絡(luò)序
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(包頭序也需要轉(zhuǎn)換)
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); //調(diào)用協(xié)議棧函數(shù)發(fā)送出去
#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
// 恢復(fù)序
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 on 2008-11-26 11:42
水 閱讀(4932)
評論(3) 編輯 收藏 引用 所屬分類:
udt分析