Skip to content

Commit

Permalink
udp socket支持软绑定目标地址 (ZLMediaKit#169)
Browse files Browse the repository at this point in the history
硬绑定(udp connect)目标地址后可能导致收不到其他地址的报文,所以新增一种可以指定目标发送地址的机制,
这样在调用Socket::send接口时不用指定目标地址,同时又不会导致收不到其他地址的报文。
此特性主要是为了解决rtsp服务器发送rtp(udp)给nat内的播放器失败的问题。
  • Loading branch information
xia-chu authored Aug 5, 2023
1 parent 79db405 commit d201652
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 6 deletions.
24 changes: 19 additions & 5 deletions src/Network/Socket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,12 @@ ssize_t Socket::send(string buf, struct sockaddr *addr, socklen_t addr_len, bool

ssize_t Socket::send(Buffer::Ptr buf, struct sockaddr *addr, socklen_t addr_len, bool try_flush) {
if (!addr) {
return send_l(std::move(buf), false, try_flush);
if (!_udp_send_dst) {
return send_l(std::move(buf), false, try_flush);
}
// 本次发送未指定目标地址,但是目标定制已通过bindPeerAddr指定
addr = (struct sockaddr *)_udp_send_dst.get();
addr_len = SockUtil::get_sock_len(addr);
}
return send_l(std::make_shared<BufferSock>(std::move(buf), addr, addr_len), true, try_flush);
}
Expand Down Expand Up @@ -864,17 +869,26 @@ bool Socket::cloneSocket(const Socket &other) {
return true;
}

bool Socket::bindPeerAddr(const struct sockaddr *dst_addr, socklen_t addr_len) {
bool Socket::bindPeerAddr(const struct sockaddr *dst_addr, socklen_t addr_len, bool soft_bind) {
LOCK_GUARD(_mtx_sock_fd);
if (!_sock_fd) {
return false;
}
if (_sock_fd->type() != SockNum::Sock_UDP) {
return false;
}
if (-1 == ::connect(_sock_fd->rawFd(), dst_addr, addr_len ? addr_len : SockUtil::get_sock_len(dst_addr))) {
WarnL << "Connect socket to peer address failed: " << SockUtil::inet_ntoa(dst_addr);
return false;
addr_len = addr_len ? addr_len : SockUtil::get_sock_len(dst_addr);
if (soft_bind) {
// 软绑定,只保存地址
_udp_send_dst = std::make_shared<struct sockaddr_storage>();
memcpy(_udp_send_dst.get(), dst_addr, addr_len);
} else {
// 硬绑定后,取消软绑定,防止memcpy目标地址的性能损失
_udp_send_dst = nullptr;
if (-1 == ::connect(_sock_fd->rawFd(), dst_addr, addr_len)) {
WarnL << "Connect socket to peer address failed: " << SockUtil::inet_ntoa(dst_addr);
return false;
}
}
return true;
}
Expand Down
6 changes: 5 additions & 1 deletion src/Network/Socket.h
Original file line number Diff line number Diff line change
Expand Up @@ -454,9 +454,10 @@ class Socket : public std::enable_shared_from_this<Socket>, public noncopyable,
* 绑定udp 目标地址,后续发送时就不用再单独指定了
* @param dst_addr 目标地址
* @param addr_len 目标地址长度
* @param soft_bind 是否软绑定,软绑定时不调用udp connect接口,只保存目标地址信息,发送时再传递到sendto函数
* @return 是否成功
*/
bool bindPeerAddr(const struct sockaddr *dst_addr, socklen_t addr_len = 0);
bool bindPeerAddr(const struct sockaddr *dst_addr, socklen_t addr_len = 0, bool soft_bind = false);

/**
* 设置发送flags
Expand Down Expand Up @@ -528,6 +529,9 @@ class Socket : public std::enable_shared_from_this<Socket>, public noncopyable,
bool _err_emit = false;
//是否启用网速统计
bool _enable_speed = false;
// udp发送目标地址
std::shared_ptr<struct sockaddr_storage> _udp_send_dst;

//接收速率统计
BytesSpeed _recv_speed;
//发送速率统计
Expand Down

0 comments on commit d201652

Please sign in to comment.