使用usrsctp作为客户端与mediasoup服务器通过UDP承载SCTP时,消息持续重传问题求助
usrsctp作为客户端与mediasoup服务器通过UDP承载SCTP时,消息持续重传问题求助
各位大佬好!我现在遇到一个折腾了好久都没解决的棘手问题,来求大家帮忙看看:
我用usrsctp作为客户端,mediasoup作为服务端,通过UDP来承载SCTP的消息传输。目前握手流程看起来是正常完成的,但每次发送消息后,明明已经收到服务端返回的SACK响应,usrsctp却一直在重传同一条消息,试了各种方法都没搞定。
我的实现流程
- 先创建UDP socket,bind到本地端口,connect到服务端的UDP端口
- 初始化usrsctp:调用
usrsctp_init(),传入本地端口和自定义的send回调(回调内部用UDP的sendto()把SCTP层的数据转发出去) - 调用
usrsctp_register_address()注册服务端的地址 - 创建SCTP socket(
usrsctp_socket()),设置为非阻塞模式,bind到mediasoup要求的5000端口,再调用usrsctp_connect()发起连接 - 启动循环:用
recvfrom()接收UDP socket的数据,再传给usrsctp_conninput()交给usrsctp处理
当前现象
- SCTP握手完全正常:能看到
INIT -> INIT_ACK -> COOKIE_ECHO -> COOKIE_ACK的完整握手流程 - 调用
usrsctp_sendv()发送消息后,确实能收到服务端返回的SACK响应,但usrsctp就是持续重传这条消息 - 试过通过设置
SCTP_PR_SCTP_RTX策略为0来禁用重传,完全无效;各种参数调整、流程修改都试过,重传问题依然存在
附完整可复现代码
#include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <usrsctp.h> #include <stdio.h> #include <string.h> #include <pthread.h> int sock; struct socket *sctp_socket; void *keypress_listener(void *arg) { getchar(); struct sctp_sendv_spa spa; memset(&spa, 0, sizeof(spa)); spa.sendv_flags = SCTP_SEND_SNDINFO_VALID; spa.sendv_sndinfo.snd_sid = 1; spa.sendv_sndinfo.snd_ppid = htonl(51); spa.sendv_sndinfo.snd_flags = SCTP_EOR; // end of message spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_RTX; spa.sendv_prinfo.pr_value = 0; const char *msg = "Hello World"; int addr_len = 1; if (usrsctp_sendv(sctp_socket, (void *)msg, strlen(msg), NULL, 0, &spa, (socklen_t)sizeof(spa), SCTP_SENDV_SPA, 0) < 0) { printf("Failed to send message"); } } int onSendSctpData( void *addr, void *data, size_t len, uint8_t tos, uint8_t setDf) { // printf("on send data. len:%d\n", len); struct sockaddr_in *remote = (struct sockaddr_in *)addr; return sendto(sock, data, len, 0, (struct sockaddr *)remote, sizeof(*remote)); } int onRecvSctpData( struct socket *socket /*sock*/, union sctp_sockstore saddr /*addr*/, void *data, size_t len, struct sctp_rcvinfo rcv, int flags, void *ulpInfo) { // printf("received sctp data\n"); return 0; } int main(int argc, char *argv[]) { // setup UDP transport sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); int local_port = 40001; int remote_port = 44444; struct sockaddr_in local_addr; memset(&local_addr, 0, sizeof(local_addr)); local_addr.sin_family = AF_INET; local_addr.sin_port = htons(local_port); local_addr.sin_addr.s_addr = INADDR_ANY; bind(sock, (struct sockaddr *)&local_addr, sizeof(local_addr)); struct sockaddr_in remote_addr; memset(&remote_addr, 0, sizeof(remote_addr)); remote_addr.sin_family = AF_INET; remote_addr.sin_port = htons(remote_port); remote_addr.sin_addr.s_addr = INADDR_ANY; // inet_addr("<ip-address>"); connect(sock, (struct sockaddr *)&remote_addr, sizeof(remote_addr)); // setup SCTP over UDP usrsctp_init(local_port, onSendSctpData, NULL); usrsctp_register_address(&remote_addr); // required, else usrsctp_bind() won't work sctp_socket = usrsctp_socket(AF_CONN, SOCK_STREAM, IPPROTO_SCTP, onRecvSctpData, NULL, 256u, &remote_addr); usrsctp_set_non_blocking(sctp_socket, 1); struct sockaddr_conn sctp_addr; memset(&sctp_addr, 0, sizeof(sctp_addr)); sctp_addr.sconn_family = AF_CONN; sctp_addr.sconn_port = htons(5000); sctp_addr.sconn_addr = &remote_addr; if (usrsctp_bind(sctp_socket, (struct sockaddr *)&sctp_addr, sizeof(sctp_addr)) < 0) { printf("bind failed"); } printf("sctp connecting..."); if (usrsctp_connect(sctp_socket, (struct sockaddr *)&sctp_addr, sizeof(sctp_addr)) < 0) { printf("connect failed"); // this appears to be normal for non-blocking } pthread_t thread; pthread_create(&thread, NULL, keypress_listener, NULL); pthread_join(thread, NULL); int addrlen = sizeof(local_addr); char buf[1024]; while (1) { ssize_t len = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *)&local_addr, &addrlen); if (len > 0) { usrsctp_conninput(&remote_addr, buf, len, 0); } } return 0; }
补充说明
- 已经提供了最小可复现示例(MRE)
- 因为localhost测试时遇到一些问题,我用了tailscale来配置远程地址
- 抓了wireshark包,能明确看到服务端返回了SACK,但客户端usrsctp还是不断发起重传
内容来源于stack exchange
相关产品推荐
相关产品推荐

