0

そのため、接続ごとに転送されるデータ量が帯域幅に与える影響を調べるために、TCP のベンチマークを行っています。そこで、必要なものを測定するために C でサーバーとクライアントを作成しました。次に、Python スクリプトを使用して実験を何度も実行しました (精度を +/- 1% にするために、100 秒間テストを実行しました。データの各ポイントについて、適切な平均を得るために実験を 33 回実行しました)。さまざまな入力を行い、結果を収集します。

私が得た結果は、帯域幅が本来あるべきものの 10% にすぎないことを除いて、ほぼ正しいように思えます (接続ごとに転送されるデータ量が多い場合に予想されるプラトーを観察することさえできます)。

このベンチマークを実行するために 1 台のコンピューターにしかアクセスできないため、localhost でテストを行っていますが、問題にはなりません。

ここに私の結果があります:

ベンチマーク結果のグラフ

ご覧のとおり、取得できる最高の帯域幅は 300 MB/秒を少し超えているようです...しかし、iperf で帯域幅テストを実行すると (同じ TCP ウィンドウ サイズを使用するようにしました)、localhost で約 3 GB/秒の帯域幅を取得します。

これが私のクライアントのコードです:

int main(int argc, char const *argv[])
{
    unsigned int size;
    unsigned int timeout;
    int sockfd;
    struct sockaddr_in server_addr;

    if(argc < 4 || argc > 5 ){
        usage();
        exit(1);
    }

    const char * ip = "127.0.0.1";
    ip = argv[3];

    int port = PORT;
    if(argc == 5) {
        port = atoi(argv[4]);
    }

    size = atoi(argv[1]);
    timeout = atoi(argv[2]);

    unsigned int count = 0;

    struct timespec start, end;

    clock_gettime(CLOCK_MONOTONIC_RAW, &start);
    clock_gettime(CLOCK_MONOTONIC_RAW, &end);

    while((end.tv_sec - start.tv_sec) < timeout) {

        // socket create and varification
        sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (sockfd == -1) {
            perror("Could not create socket\n");
            exit(0);
        }

        bzero(&server_addr, sizeof(server_addr));

        // assign IP, PORT of the server
        server_addr.sin_family = AF_INET;
        server_addr.sin_addr.s_addr = inet_addr(ip);
        server_addr.sin_port = htons(port);

        // connect the client socket to server socket
        if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) != 0) {
            perror("connection with the server failed");
            exit(1);
        }

        unsigned int nread = 0;
        unsigned int nreadcum = 0;
        char* buf = malloc(size);
        char* bufbuf = buf;

        while(nreadcum < size){
            nread = read(sockfd, bufbuf, size-nreadcum);
            nreadcum += nread;
            bufbuf+=nread;
        }
        // close connection
        close(sockfd);
        count++;
        clock_gettime(CLOCK_MONOTONIC_RAW, &end);
        free(buf);
    }


    uint64_t sec = (end.tv_sec - start.tv_sec);
    double bandwidth = (count*size)/sec;

    printf("%u,%lf,%u,%lu\n", size, bandwidth, count, sec);

    return 0;
}

そして、ここに私のサーバーのコードがあります:

int serv_sock_fd;

int main(int argc, char const *argv[])
{
    int size;
    struct sockaddr_in serv_addr;
    struct sockaddr_in client_addr;
    int bound_port;

    if(argc != 2){
        usage();
        exit(1);
    }

    size = atoi(argv[1]);

    int serv_sock_fd = socket(AF_INET,SOCK_STREAM,0);
    int true = 1;
    setsockopt(serv_sock_fd,SOL_SOCKET,SO_REUSEADDR,&true,sizeof(int));
    if(serv_sock_fd == -1) {
        perror("Failed to open server socket");
        exit(1);
    }

    bzero(&serv_addr, sizeof(serv_addr));

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    serv_addr.sin_port = htons(PORT);

    // Bind socket to the chosen port
    if ((bound_port = bind(serv_sock_fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr))) <0){
        perror("Could not bind socket to local port");
        exit(1);
    }

    // Listen on the port
    if (listen(serv_sock_fd, 16))
    {
        perror("Could not listen");
        exit(1);
    }

    signal(SIGINT, sigint_handler);

    printf("Waiting for connection on %d ...\n", PORT);

    int returned = 1;


    while(returned) {
        printf(".\n");
        int new_socket_fd;
        unsigned int client_addr_len = sizeof(client_addr);
        if ((new_socket_fd = accept(serv_sock_fd, (struct sockaddr *)&client_addr,
                            &client_addr_len))<0) {
                perror("Could not accept client connection");
                exit(1);
            }
        printf("connection received, start sending ... ");
        char * payload = sequence_payload(size);
        returned = write(new_socket_fd, payload, size);
        printf("finished sending\n");
        printf("Returned value = %d\n", returned);
        close(new_socket_fd);
        free(payload);
    }


    close(serv_sock_fd);
    return 0;
}

char * sequence_payload(int size) {
    char * payload = malloc(size);
    for (int i = 0; i < size; i++)
    {
        payload[i] = i%256;
    }
    return payload;
}

基本的に私のコードが行っていることは次のとおりです。

  • サーバーの場合: クライアントが接続するのを待ち、必要なサイズのダミー ペイロードを送信し、そのクライアントへの接続を閉じます。これを繰り返します。
  • クライアントの場合:サーバーへの接続を開き、サーバーが接続を閉じるまでサーバーが送信しているものを読み取り、決定されたタイムアウトに達するまで繰り返します。

帯域幅を計算するには、 を実行するだけです(number_of_connections_completed * size_transferred_by_connection) / duration_of_all_transfers。Cでオーバーフローが発生しないように、Pythonを使用して帯域幅を計算します。

TLDR:私の C プログラムで得られる帯域幅は、localhost の帯域幅の 10 分の 1 です。その問題の原因は何ですか?

4

1 に答える 1