做io测试

使用 send / recv 做 IO 性能测试(TCP)

send/recv 是 Linux socket 原生接口,适合做用户态TCP IO吞吐、延迟测试 ,区别于 epoll/io_uring,这里给最简单的阻塞版本,再给性能测试思路。 原理:服务端 recv,客户端 send,传输固定大小数据,统计耗时、带宽。

一、完整C代码(阻塞TCP,send/recv 测试)

server.c(接收端,recv)

复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <time.h>

#define PORT 8888
#define BUF_SIZE (1<<20) // 1MB buffer

int main() {
    int server_fd, new_socket;
    struct sockaddr_in addr;
    socklen_t addrlen = sizeof(addr);
    char *buf = malloc(BUF_SIZE);

    server_fd = socket(AF_INET, SOCK_STREAM, 0);
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = INADDR_ANY;
    addr.sin_port = htons(PORT);

    bind(server_fd, (struct sockaddr*)&addr, sizeof(addr));
    listen(server_fd, 1);
    printf("server listen on %d\n", PORT);

    new_socket = accept(server_fd, (struct sockaddr*)&addr, &addrlen);
    printf("client connected\n");

    long long total_recv = 0;
    clock_t start = clock();

    while (1) {
        int n = recv(new_socket, buf, BUF_SIZE, 0);
        if (n <= 0) break;
        total_recv += n;
    }

    clock_t end = clock();
    double sec = (double)(end - start)/CLOCKS_PER_SEC;
    printf("recv total: %lld bytes, time: %.2fs, bw: %.2f MB/s\n",
           total_recv, sec, total_recv / sec / (1<<20));

    close(new_socket);
    close(server_fd);
    free(buf);
    return 0;
}

client.c(发送端,send)

复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>

#define PORT 8888
#define BUF_SIZE (1<<20)
#define SEND_TOTAL (10LL << 30) // 10GB 测试流量

int main() {
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in serv_addr;
    char *buf = malloc(BUF_SIZE);
    memset(buf, 'A', BUF_SIZE);

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT);
    inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr);

    connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
    printf("connected to server\n");

    long long remain = SEND_TOTAL;
    clock_t start = clock();

    while (remain > 0) {
        int send_len = (remain > BUF_SIZE) ? BUF_SIZE : remain;
        int n = send(sock, buf, send_len, 0);
        if (n <= 0) {
            perror("send");
            break;
        }
        remain -= n;
    }

    clock_t end = clock();
    double sec = (double)(end - start)/CLOCKS_PER_SEC;
    printf("send total: %lld bytes, time: %.2fs, bw: %.2f MB/s\n",
           SEND_TOTAL, sec, SEND_TOTAL / sec / (1<<20));

    close(sock);
    free(buf);
    return 0;
}

二、编译 & 运行

复制代码
gcc server.c -o server -O2
gcc client.c -o client -O2

窗口1(服务端)

复制代码
./server

窗口2(客户端)

复制代码
./client

默认本地回环测试 10GB 流量,测 TCP 吞吐。 改 127.0.0.1 换成远端IP,测跨机器网络IO。

三、send/recv 关键坑(做IO测试必须注意)

  1. send 不代表数据已经送到对端 send 只是拷贝到内核 socket send buffer,成功返回仅代表拷贝完成;真正收完是对端 recv。

    所以吞吐统计一定要以 server recv 累计字节为准,client send 的计数会偏乐观。

  2. send/recv 返回值永远要检查 TCP是字节流,不保证一次send多少就一次recv多少 。 send() 返回可能小于传入长度(部分发送),上面代码已经处理了剩余数据。

  3. buffer 大小影响测试结果 调整 BUF_SIZE:4k/64k/1M/4M,用来测试不同应用层缓冲区对IO的影响。

  4. 阻塞 vs 非阻塞 上面是阻塞socket。 非阻塞:fcntl(sock, F_SETFL, O_NONBLOCK),此时 send/recv 可能返回 -1,errno=EAGAIN,需要循环重试。适合高并发IO测试。

  5. socket buffer 调优(提升上限)

    临时修改内核tcp缓冲区

    sysctl -w net.core.rmem_max=16777216
    sysctl -w net.core.wmem_max=16777216

代码里也可以用 setsockopt 设置 SO_RCVBUF / SO_SNDBUF。

参考链接 :0voice · GitHub

相关推荐
真好啊又活了一天5 小时前
服务器和虚机配置IPV6
运维·服务器·github
AR-26710-5 小时前
Linux Day33——定时任务+lvm
linux·运维
墨痕诉清风6 小时前
SSRF漏洞实战记录+OSS桶命令执行+MCP漏洞
linux·服务器·数据库
byte轻骑兵6 小时前
实战 4:BlueZ 源码中添加自定义设备过滤规则
linux·物联网·bluez·电脑蓝牙·嵌入式蓝牙
布莱克6056 小时前
Swift 常量详解:从 let 到编译期优化
服务器·开发语言·ssh·swift·常量·let
略懂而已6 小时前
安装SSL后网站速度变慢?
网络·网络协议·ssl
瓦瓦gogo7 小时前
从一个 TypeScript 函数开始理解 MCP 协议
linux·ubuntu·typescript
云上工程笔记7 小时前
RDMA / IB 高速互联 GPU 云对比:多机训练网络性能与价格
网络·gpu算力·gpu
鱼听禅8 小时前
Ubuntu安装YOLOv8进行菌落识别训练
linux·python·yolo·ubuntu
测试界的小码农8 小时前
【Linux 命令实战(04):文件内容查看,掌握 cat、less、head、tail】
linux·服务器·less