尝试发送 TCP 数据包并将其接收回来并在客户端+服务器应用程序中计算时间

问题描述 投票:0回答:1

我有一个应用程序可以将 30k 字节数据包发送到服务器,接收回来(100 次尝试)并计算其平均时间。

它必须有 2 种不同类型的套接字:UDP 和 TCP。使用 UDP 时,它工作正常,但使用 TCP 时,它会在最后一段时间(客户端)循环。我假设 TCP 的工作方式与 UDP 不同,并且打包发送的数据与我收到的数据不同。

请看我的代码:

客户端(必须第二个运行)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/time.h>
#include <errno.h>

#define BUFFER_SIZE 1000
#define ATTEMPTS 10

char buf[BUFFER_SIZE];

/*
argv[1] - nazwa hosta
argv[2] - numer portu UDP
argv[3] - numer portu TCP
*/

int main(int argc, char **argv)
{
    struct sockaddr_in endpoint;
    int sdsocket, sdsocket2, addrlen, i, received, j=0, r_sendto, r_recvfrom;
    struct hostent *he;
    struct timeval time_b, time_e;

    if (argc<4) {
        printf("podaj nazwe hosta i numery portu jako parametry (1 UDP, 2 TCP)\n");
        return 1;
    }

    he = gethostbyname(argv[1]);
    if (he == NULL) {
        printf("Nieznany host (unknown kost): %s\n",argv[1]);
        return 0;
    }

    memset(&endpoint, 0, sizeof(endpoint));

    endpoint.sin_family = AF_INET;
    endpoint.sin_port = htons(atoi(argv[2]));
    endpoint.sin_addr = *(struct in_addr*) he->h_addr;
    addrlen = sizeof(struct sockaddr_in);

    ////////////// UDP //////////////////
    gettimeofday(&time_b, NULL);
    if ((sdsocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0){
        perror("socket UDP() nie powiodl sie");
        return 1;
    }

    while(ATTEMPTS>j){
        r_sendto = sendto(sdsocket,
                            buf,
                            BUFFER_SIZE,
                            0,
                            (struct sockaddr*) &endpoint,
                            addrlen);
        if (r_sendto == -1) {
            perror("sendto() nie powiodl sie (failed)\n");
            //close(sdsocket); //?
            return 1;
        }
        
        r_recvfrom = recvfrom(sdsocket,
                            buf,
                            BUFFER_SIZE,
                            0,
                            (struct sockaddr*) &endpoint,
                            &addrlen);
        if (r_recvfrom == -1){
            perror("recvfrom() nie powidl sie (failed)\n");
            break;
        }
        j++; 
    }
    close(sdsocket);
    gettimeofday(&time_e, NULL);


    printf("Czas dla 30k-bajtowych bloków (UDP): %.6f s\n",
        (((double) (time_e.tv_sec - time_b.tv_sec) * 1000000) +
        ((double) (time_e.tv_usec - time_b.tv_usec)))
        / (1000000.0 * ATTEMPTS));

    ////////////// TCP //////////////////

    sleep(2);

    endpoint.sin_port = htons(atoi(argv[3]));

    if ((sdsocket2 = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("socket TCP() nie powiodl sie (failed)\n");
        return 1;
    }
 
    gettimeofday(&time_b, NULL);
    
    if (connect(sdsocket2,(struct sockaddr*) &endpoint, addrlen) < 0) {
        perror("connect() nie powiodl sie");
        return 0;
    }

    for (i=0; i<ATTEMPTS; i++) {
        send(sdsocket2, buf, BUFFER_SIZE, 0);
        received = 0;

        while (received < BUFFER_SIZE)
        {
            printf("test %d\n", i);

            int ret = recv(sdsocket2,
                            buf+received,
                            BUFFER_SIZE-received,
                            0);
            
            if (ret <=0){
                if (ret = 0){
                    printf("ret=0 - serwer zamknal\n");
                }
                else{
                    fprintf(stderr, "recv error: %s\n", strerror(errno));
                }
             break;
            }
           received += ret; 
        }
       
    }
    close(sdsocket2);
    gettimeofday(&time_e, NULL);

    printf("Czas dla 30k-bajtowych bloków (TCP): %.6f s\n",
        (((double) (time_e.tv_sec - time_b.tv_sec) * 1000000) +
        ((double) (time_e.tv_usec - time_b.tv_usec)))
        / (1000000.0 * ATTEMPTS));
    return 0;
}

服务器(必须先运行):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/time.h>

#define BUFFER_SIZE 1000
#define ATTEMPTS 10

char buf[BUFFER_SIZE];

/*
argv[1] - numer portu dla UDP
argv[2] - numer portu dla TCP
*/
int main(int argc, char **argv) {
    struct sockaddr_in myaddr, client_addr;
    int sdsocketUDP, sdsocketTCP; //sdsocket dla UDP/TCP
    int addrlen, received, i, sdconnection;
    socklen_t client_addrlen;

    if (argc < 3) {
        printf("podaj numer portu jako parametry (1 UDP, 2 TCP)\n");
        return 1;
    }
    sdsocketUDP = socket(AF_INET, SOCK_DGRAM, 0);
    addrlen = sizeof(struct sockaddr_in);

    myaddr.sin_family = AF_INET;
    myaddr.sin_port = htons(atoi(argv[1]));
    myaddr.sin_addr.s_addr = htonl(INADDR_ANY);

    if (bind(sdsocketUDP, (struct sockaddr*) &myaddr, addrlen) < 0) {
        perror("bind() nie powiodl sie (failed)\n");
        return 1;
    }

    client_addrlen = sizeof(struct sockaddr_in); //???
    printf("test1\n");
    ////////////// UDP //////////////////
    memset(buf, 0, BUFFER_SIZE);
    for (i = 0; i < ATTEMPTS; i++) {
        received = recvfrom(sdsocketUDP,
                            buf,
                            BUFFER_SIZE,
                            0,
                            (struct sockaddr*) &client_addr,
                            &client_addrlen);

        if (received == -1) {
            perror("recvfrom() nie powiodl sie");
           // close(sdsocketUDP); //?
            return 1;
        }

        sendto(sdsocketUDP,
               buf,
               BUFFER_SIZE,
               0,
               (struct sockaddr*) &client_addr,
               client_addrlen);
    }
    close(sdsocketUDP);
    ////////////// TCP //////////////////
    
    //myaddr.sin_family = AF_INET;
    myaddr.sin_port = htons(atoi(argv[2]));
    //myaddr.sin_addr.s_addr = INADDR_ANY;
    sdsocketTCP = socket(AF_INET, SOCK_STREAM, 0);
    // zmienione addrlen na sizeof(myaddr)
    if (bind(sdsocketTCP, (struct sockaddr*) &myaddr, addrlen) < 0) {
    perror("bind() nie powiodl sie (failed)\n");
    return 1;
    }

    client_addrlen = sizeof(struct sockaddr_in);
  
    if (sdsocketTCP < 0) {
        perror("socket TCP() nie powiodl sie (failed)\n");
        return 1;
    }

    if (listen(sdsocketTCP, 10) < 0) {
        perror("listen() nie powiodl sie (failed)\n");
        return 1;
    }

    printf("Czekam na polaczenie (I am waiting for connection)...\n");

    while ((sdconnection =
                accept(sdsocketTCP,
                       (struct sockaddr*) &client_addr,
                       &client_addrlen)) >= 0)
    {

        memset(buf, 0, BUFFER_SIZE);
        received = 0;
        while (received < BUFFER_SIZE) {
            received += recv(sdconnection,
                             buf + received,
                             BUFFER_SIZE - received,
                             0);
               
                                   
        }
        send(sdconnection, buf, BUFFER_SIZE, 0);
        close(sdconnection);   
    }
    close(sdsocketTCP);
    return 0;
}

我尝试更改块被分区时发送的字节数,在客户端中添加睡眠以防服务器未按时响应/应答,但没有成功。

聊天GPT无法说出答案或提示。我认为问题在于 TCP 如何工作。

干杯。

c tcp udp packet
1个回答
0
投票

您的 TCP 服务器似乎在收到 BUFFER_SIZE 字节后关闭了已接受的 TCP 连接:

    while ((sdconnection =
            accept(sdsocketTCP,
                   (struct sockaddr*) &client_addr,
                   &client_addrlen)) >= 0)
    {
        ...
        while (received < BUFFER_SIZE) {
            ...
        }
        ....
        close(sdconnection);   
    }

由于 TCP 客户端尝试使用同一个 TCP 连接 30 * BUFFER_SIZE 字节,服务器过早关闭连接,并开始等待下一个连接。

© www.soinside.com 2019 - 2024. All rights reserved.