socket缓冲区溢出

Viewed 7

重现步骤

我在测试视频通话时 发现丢帧特别严重 进行了一些列的排查 发现socket本身似乎有问题

通过测试代码发现了大量的缓冲区溢出 我尝试换了不同的服务器

我还分别测试了wifi网卡和4G网卡 全都这样 无法正常的进行视频通话

不可能才四五百KB/s的速率就不行了啊 好久以前我测试过1M/s都是没问题的

服务器1配置如下 ↓
image.png

服务器2配置如下 ↓
image.png

期待结果和实际结果

软硬件版本信息

01科技K230开发板 + EC200A移远minipcie USB网卡 + RTOS_ONLY

错误日志

通过wifi往腾讯云上传日志如下 ↓
image.png

通过4G网卡移远 EC200A 往雨云上传日志如下 ↓
image.png

尝试解决过程

补充材料

测试代码如下

1 Answers
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <unistd.h>

#define TARGET_IP "27.25.142.58"
// #define TARGET_IP        "162.14.198.185"
#define TARGET_PORT      30100
#define BUFFER_SIZE      1400
#define TARGET_RATE_KB_S 500 // 目标发送速率(KB/s)
#define SEND_TIMEOUT_SEC 5 // 发送超时时间(秒)

volatile int keep_running = 1;

void int_handler(int sig)
{
    keep_running = 0;
    printf("\n接收到中断信号,准备退出...\n");
}

// 创建非阻塞连接
int connect_server()
{
    int sock_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (sock_fd < 0) {
        perror("socket创建失败");
        return -1;
    }

    // 设置非阻塞
    int flags = fcntl(sock_fd, F_GETFL, 0);
    fcntl(sock_fd, F_SETFL, flags | O_NONBLOCK);

    // 设置发送超时
    struct timeval tv = { SEND_TIMEOUT_SEC, 0 };
    setsockopt(sock_fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));

    // 连接服务器
    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port   = htons(TARGET_PORT);
    inet_pton(AF_INET, TARGET_IP, &server_addr.sin_addr);

    printf("连接 %s:%d...\n", TARGET_IP, TARGET_PORT);

    if (connect(sock_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
        if (errno != EINPROGRESS) {
            perror("连接失败");
            close(sock_fd);
            return -1;
        }

        // 等待连接完成
        fd_set wfds;
        FD_ZERO(&wfds);
        FD_SET(sock_fd, &wfds);
        tv.tv_sec  = 5;
        tv.tv_usec = 0;

        if (select(sock_fd + 1, NULL, &wfds, NULL, &tv) <= 0) {
            perror("连接超时");
            close(sock_fd);
            return -1;
        }
    }

    printf("已连接\n");
    return sock_fd;
}

int main(int argc, char* argv[])
{
    signal(SIGINT, int_handler);

    // 初始化缓冲区
    unsigned char buffer[BUFFER_SIZE];
    memset(buffer, 12, BUFFER_SIZE);

    // 连接服务器
    int sock_fd = connect_server();
    if (sock_fd < 0)
        return -1;

    printf("开始发送数据 (速率:%d KB/s, 按Ctrl+C停止)\n", TARGET_RATE_KB_S);

    // 计算发送间隔
    long delay_us = (long)((double)BUFFER_SIZE / (TARGET_RATE_KB_S * 1024) * 1000000);

    // 统计变量
    unsigned long  total_bytes        = 0;
    int            packets_sent       = 0;
    int            consecutive_errors = 0;
    struct timeval start_time, current_time, last_success;
    gettimeofday(&start_time, NULL);
    last_success = start_time;

    // 发送循环
    while (keep_running) {
        int bytes_sent = send(sock_fd, buffer, BUFFER_SIZE, 0);

        if (bytes_sent < 0) {
            if (errno == EAGAIN || errno == EWOULDBLOCK) {
                printf("缓冲区满\n");
                // 缓冲区满,检查是否需要重连
                gettimeofday(&current_time, NULL);
                double idle_time = (current_time.tv_sec - last_success.tv_sec)
                    + (current_time.tv_usec - last_success.tv_usec) / 1000000.0;

                if (idle_time > SEND_TIMEOUT_SEC) {
                    printf("发送超时(%.1f秒),重连...\n", idle_time);
                    close(sock_fd);
                    sleep(1);

                    sock_fd = connect_server();
                    if (sock_fd < 0)
                        break;

                    gettimeofday(&last_success, NULL);
                    consecutive_errors = 0;
                    continue;
                }

                usleep(100000); // 等待100ms
                consecutive_errors++;

                if (consecutive_errors > 10) {
                    sleep(1); // 连续失败时等待更久
                    consecutive_errors = 0;
                }
                continue;
            } else {
                printf("发送错误: %s\n", strerror(errno));
                break;
            }
        } else if (bytes_sent == 0) {
            printf("连接关闭\n");
            break;
        }

        // 发送成功
        consecutive_errors = 0;
        gettimeofday(&last_success, NULL);
        total_bytes += bytes_sent;
        packets_sent++;

        // 每10个包更新状态
        if (packets_sent % 100 == 0) {
            gettimeofday(&current_time, NULL);
            double elapsed
                = (current_time.tv_sec - start_time.tv_sec) + (current_time.tv_usec - start_time.tv_usec) / 1000000.0;

            printf("已发送: %d包, %luB, 速率: %.2fKB/s\n", packets_sent, total_bytes, (total_bytes / 1024.0) / elapsed);
        }

        // 控制发送速率
        usleep(delay_us);
    }

    // 统计结果
    gettimeofday(&current_time, NULL);
    double total_time
        = (current_time.tv_sec - start_time.tv_sec) + (current_time.tv_usec - start_time.tv_usec) / 1000000.0;

    printf("\n总计: %d包, %luB, 时间: %.2f秒, 平均速率: %.2fKB/s\n", packets_sent, total_bytes, total_time,
           (total_bytes / 1024.0) / total_time);

    close(sock_fd);
    return 0;
}