SRT源码分析--CChanel分析

时间:2024-12-18 07:34:14

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;

}