Search code examples
ctcpudppacket

trying to send TCP packet and recieve it back and count time in client+server app


I have app to do that send 30k byte packet in to server, receive it back (100 attempts) and counts average time of that.

It has to have 2 dif type of sockets: UDP and TCP. With UDP its working fine, but with TCP it's looping in a last while (client-side). I assume that TCP is working differently than UDP, and the packed send isn't the same that i recieve.

Please look at my code:

client (has to be run second)

#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;
}

server (has to be run first):

#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;
}

I tried changing number of bytes send in case of blocks being partitioned, adding sleep in client in case server isn't responding/answering on time, but didn't work.

Chat GPT can't tell the answer or hint. I think issue is with it how TCP works.

Cheers.


Solution

  • Your TCP server seems to close the accepted TCP connection after receiving BUFFER_SIZE bytes:

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

    Because the TCP client try to use the same TCP connection for ATTEMPTS * BUFFER_SIZE bytes, the server closes the connection too early, and starts waiting next connection.

    Quick and dirty(?) fix for the server would be:

    Echo all data from the client until the TCP connection is closed (recv() returns 0 or -1). For example something like this:

        while ((sdconnection =
                accept(sdsocketTCP,
                       (struct sockaddr*) &client_addr,
                       &client_addrlen)) >= 0)
        {
            while (1)
                int len = recv(sdconnection, buf, BUFFER_SIZE, 0);                
                if (len <= 0)
                     break;
                send(sdconnection, buf, len, 0);
            };
            close(sdconnection);   
        }