You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.07 07:23:10