悠扬随风 发表于 2024-12-18 00:00:42

SRT源码分析--CChanel分析

void srt::CChannel::createSocket(int family)
{
m_iSocket = ::socket(family, SOCK_DGRAM, IPPROTO_UDP);
}

void srt::CChannel::open(int family)
{
// 创建一个 socket,利用传入的协议族(family)参数。
createSocket(family);

// 界说 addrinfo 结构体,用于指定 getaddrinfo 函数的搜刮条件。
addrinfo hints;
// 界说 addrinfo 结构体指针,用于存储 getaddrinfo 函数的返回效果。
addrinfo* res;

// 将 hints 结构体初始化为 0。
memset(&hints, 0, sizeof(struct addrinfo));

// 设置搜刮条件。
hints.ai_flags = AI_PASSIVE; // 利用被动模式,通常用于服务器端,表示地址适用于绑定。
hints.ai_family = family; // 设置协议族,如 AF_INET、AF_INET6 等。
hints.ai_socktype = SOCK_DGRAM; // 设置 socket 类型为 UDP。

// 利用 getaddrinfo 函数分析当地地址,返回效果存储在 res 指针中。
const int eai = ::getaddrinfo(NULL, "0", &hints, &res);

// 查抄 getaddrinfo 是否乐成。如果失败,不实行绑定操作,直接跳到设置 UDP 套接字选项。
if (eai != 0)
{
// 如果 getaddrinfo 失败,这里没有处理错误,而是直接跳过绑定步骤。
// 这大概不是最佳实践,由于通常应该处理错误,例如记录日志或抛出非常。
}

// 绑定 socket 到获取的地址,这里缺少了对 getaddrinfo 失败的查抄。
// 如果 getaddrinfo 失败,res 将是 NULL,这将导致绑定操作失败。
if (0 != ::bind(m_iSocket, res->ai_addr, (socklen_t)res->ai_addrlen))
{
// 如果 bind 函数失败,这里没有处理错误,而是直接跳过设置 UDP 套接字选项。
// 同样,这大概不是最佳实践,由于通常应该处理错误。
}

// 设置 UDP socket 选项,如缓冲区大小等。
setUDPSockOpt();
}

void srt::CChannel::open(int family)
{
// 创建一个 socket,利用传入的协议族(family)参数。
createSocket(family);

// sendto 或 WSASendTo 也会自动绑定 socket,以是这里不需要显式绑定。
addrinfo hints; // 界说 addrinfo 结构体,用于指定 getaddrinfo 函数的搜刮条件。
addrinfo* res; // 界说 addrinfo 结构体指针,用于存储 getaddrinfo 函数的返回效果。

// 将 hints 结构体初始化为 0。
memset(&hints, 0, sizeof(struct addrinfo));

// 设置搜刮条件。
hints.ai_flags = AI_PASSIVE; // 利用被动模式,通常用于服务器端,表示地址适用于绑定。
hints.ai_family = family; // 设置协议族,如 AF_INET、AF_INET6 等。
hints.ai_socktype = SOCK_DGRAM; // 设置 socket 类型为 UDP。

// 利用 getaddrinfo 函数分析当地地址,返回效果存储在 res 指针中。
const int eai = ::getaddrinfo(NULL, "0", &hints, &res);
if (eai != 0)
{
// 如果 getaddrinfo 函数失败,抛出非常。这里的错误码 eai 被通报给非常。
throw CUDTException(MJ_SETUP, MN_NORES, eai);
}

// 将 res 指向的地址信息用于绑定 socket。
// Windows 下 ai_addrlen 类型为 size_t(无符号),而 bind 函数需要 int 类型。
if (0 != ::bind(m_iSocket, res->ai_addr, (socklen_t)res->ai_addrlen))
{
// 如果 bind 函数失败,开释 res 指向的地址信息并抛出非常。
::freeaddrinfo(res);
throw CUDTException(MJ_SETUP, MN_NORES, NET_ERROR);
}
// 将绑定的地址信息生存到 m_BindAddr 成员变量中。
m_BindAddr = sockaddr_any(res->ai_addr, (sockaddr_any::len_t)res->ai_addrlen);

#ifdef SRT_ENABLE_PKTINFO
// 如果启用了 SRT_ENABLE_PKTINFO 特性,标志为绑定掩码。
m_bBindMasked = true;
#endif

// 开释 getaddrinfo 函数分配的地址信息。
::freeaddrinfo(res);

// 利用日志记录绑定到的当地地址。
HLOGC(kmlog.Debug, log << "CHANNEL: Bound to local address: " << m_BindAddr.str());

// 设置 UDP socket 选项,如缓冲区大小等。
setUDPSockOpt();
}

void srt::CChannel::attach(UDPSOCKET udpsock, const sockaddr_any& udpsocks_addr)
{
// 这行解释说明在调用此函数之前,已经利用 getsockname() 获取了 socket 的名称,
// 并将效果存储在 udpsocks_addr 中。

// 将传入的 UDP socket 描述符赋值给类的成员变量 m_iSocket。
m_iSocket = udpsock;

// 将传入的 UDP socket 地址赋值给类的成员变量 m_BindAddr。
m_BindAddr = udpsocks_addr;

// 调用 setUDPSockOpt 函数来设置 UDP socket 选项,如缓冲区大小等。
setUDPSockOpt();
}

void srt::CChannel::setUDPSockOpt()
{
// BSD体系如果哀求的缓冲区大小凌驾了体系的最大值,setsockopt会失败。
// 这里界说了一个名为maxsize的变量,其值为64000,用作缓冲区大小的上限。
int maxsize = 64000;

// 实行设置UDP接收缓冲区的大小为m_mcfg.iUDPRcvBufSize。
// 如果设置失败(返回值非0),则实行将接收缓冲区大小设置为体系最大值maxsize。
if (0 != ::setsockopt(
m_iSocket, SOL_SOCKET, SO_RCVBUF, (const char*)&m_mcfg.iUDPRcvBufSize, sizeof m_mcfg.iUDPRcvBufSize))
{
::setsockopt(m_iSocket, SOL_SOCKET, SO_RCVBUF, (const char*)&maxsize, sizeof maxsize);
}

// 实行设置UDP发送缓冲区的大小为m_mcfg.iUDPSndBufSize。
// 如果设置失败(返回值非0),则实行将发送缓冲区大小设置为体系最大值maxsize。
if (0 != ::setsockopt(
m_iSocket, SOL_SOCKET, SO_SNDBUF, (const char*)&m_mcfg.iUDPSndBufSize, sizeof m_mcfg.iUDPSndBufSize))
{
::setsockopt(m_iSocket, SOL_SOCKET, SO_SNDBUF, (const char*)&maxsize, sizeof maxsize);
}
}

int srt::CChannel::getSndBufSize() //设置发送buffer大小
{
socklen_t size = (socklen_t)sizeof m_mcfg.iUDPSndBufSize;
::getsockopt(m_iSocket, SOL_SOCKET, SO_SNDBUF, (char*)&m_mcfg.iUDPSndBufSize, &size);
return m_mcfg.iUDPSndBufSize;
}

int srt::CChannel::getRcvBufSize() //获取接收buffer大小
{
socklen_t size = (socklen_t)sizeof m_mcfg.iUDPRcvBufSize;
::getsockopt(m_iSocket, SOL_SOCKET, SO_RCVBUF, (char*)&m_mcfg.iUDPRcvBufSize, &size);
return m_mcfg.iUDPRcvBufSize;
}
void srt::CChannel::getSockAddr(sockaddr_any& w_addr) const
{
// getsockname 函数只需要充足的目标空间来复制套接字名称,
// 它不需要与地址族相关联。因此,任何名称的最大空间,
// 不论眷属如何,都可以胜任。
socklen_t namelen = (socklen_t)w_addr.storage_size(); // 获取 w_addr 提供的存储空间大小。
::getsockname(m_iSocket, (w_addr.get()), (&namelen)); // 利用 getsockname 函数获取当前套接字的当地地址。
w_addr.len = namelen; // 更新 w_addr 的长度为获取的地址长度。
}
void srt::CChannel::getPeerAddr(sockaddr_any& w_addr) const
{
// 获取 w_addr 提供的存储空间大小。
socklen_t namelen = (socklen_t)w_addr.storage_size();
// 利用 getpeername 函数获取当前套接字的远程(对端)地址。
::getpeername(m_iSocket, (w_addr.get()), (&namelen));
// 更新 w_addr 的长度为获取的地址长度。
w_addr.len = namelen;
}





免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: SRT源码分析--CChanel分析