socket sends client-server file

I coded an application where a client sends a file to the server with a socket that uses the tcp protocol.

My server is multithreaded (with Pthread).

There's just one problem, copy the file to the server is smaller (about 2ko loss) as the original file. Why?

Here is my client code, which starts typing ./client filename filenamecopy

#include <netdb.h>
#include <netinet/in.h>
#include <string.h>
#include <stdio.h>
 
 
int fileSEND(char *server, int PORT, char *lfile, char *rfile){
 
    int socketDESC;
    struct sockaddr_in serverADDRESS;
    struct hostent *hostINFO;
    FILE * file_to_send;
    int ch;
    char toSEND[1];
    char remoteFILE[4096];
    int count1=1,count2=1, percent;
 
    hostINFO = gethostbyname(server);
    if (hostINFO == NULL) {
        printf("L'adresse ip du serveur n'est pas accesible\n");
        return 1;
    }
 
    socketDESC = socket(AF_INET, SOCK_STREAM, 0);
    if (socketDESC < 0) {
        printf("Erreur création socket\n");
        return 1;
    }
 
    serverADDRESS.sin_family = hostINFO->h_addrtype;
    memcpy((char *) &serverADDRESS.sin_addr.s_addr, hostINFO->h_addr_list[0], hostINFO->h_length);
    serverADDRESS.sin_port = htons(PORT);
 
    if (connect(socketDESC, (struct sockaddr *) &serverADDRESS, sizeof(serverADDRESS)) < 0) {
        printf("Erreur de connection\n");
        return 1;
    }
 
 
    file_to_send = fopen (lfile,"r");
    if(!file_to_send) {
        printf("Erreur de lecture du fichier\n");
        close(socketDESC);
        return 0;
    } else {
    long fileSIZE;
    fseek (file_to_send, 0, SEEK_END); fileSIZE =ftell (file_to_send);
    rewind(file_to_send);
 
    sprintf(remoteFILE,"FBEGIN:%s:%i\r\n", rfile, fileSIZE);
    send(socketDESC, remoteFILE, sizeof(remoteFILE), 0);
 
    percent = fileSIZE / 100;
    while((ch=getc(file_to_send))!=EOF){
        toSEND[0] = ch;
        send(socketDESC, toSEND, 1, 0);
        if( count1 == count2 ) {
            printf("33[0;0H");
            printf( "\33[2J");
            printf("Nom du fichier: %s\n", lfile);
            printf("Taille du fichier: %i Kb\n", fileSIZE / 1024);
            printf("Poucentage : %d%% ( %d Kb)\n",count1 / percent ,count1 / 1024);
            count1+=percent;
        }
        count2++;
 
    }
    }
    fclose(file_to_send);
    close(socketDESC);
return 0;
}
 
int main(int argc, char* argv[])
{
    fileSEND("127.0.0.1", 31338, argv[1], argv[2]);
    return 0;
}

and the server, which launches just by ./server

#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <string.h>
#include <stdio.h>
#include <pthread.h>
 
#define PORT 31338
 
int parseARGS(char **args, char *line){
    int tmp=0;
    args[tmp] = strtok( line, ":" );
    while ( (args[++tmp] = strtok(NULL, ":" ) ) != NULL );
    return tmp - 1;
}
 
int client(void *ptr){
    int  connectSOCKET;
    connectSOCKET = (int ) ptr;
    char recvBUFF[4096];
    char *filename, *filesize;
    FILE * recvFILE;
    int received = 0;
    char tempstr[4096];
    char *header[4096];
 
    /*int i=0;
    while(i<993199) {
    i++;*/
    while(1){
        if( recv(connectSOCKET, recvBUFF, sizeof(recvBUFF), 0) ){
            if(!strncmp(recvBUFF,"FBEGIN",6)) {
                recvBUFF[strlen(recvBUFF) - 2] = 0;
                parseARGS(header, recvBUFF);
                filename = header[1];
                filesize = header[2];
                printf("Fichier: %s\n", filename);
                printf("Taille: %d Kb\n", atoi(filesize) / 1024);
        }
        recvBUFF[0] = 0;
        recvFILE = fopen ( filename,"w" );
        while(1){
            if( recv(connectSOCKET, recvBUFF, 1, 0) != 0 ) {
                fwrite (recvBUFF , sizeof(recvBUFF[0]) , 1 , recvFILE );
                received++;
                recvBUFF[0] = 0;
                } else {
                printf("Progression: %s [ %d of %s bytes]\n", filename, received , filesize);
                return 0;
                }
            }
            return 0;
        } else {
        printf("Client déconnecté\n");
        }
    return 0;
    }
}
 
 
int main()
{
    int socketINDEX = 0;
    int listenSOCKET, connectSOCKET[4096];
    socklen_t clientADDRESSLENGTH[4096];
    struct sockaddr_in clientADDRESS[4096], serverADDRESS;
    pthread_t threads[4096];
 
    listenSOCKET = socket(AF_INET, SOCK_STREAM, 0);
    if (listenSOCKET < 0) {
        printf("Peut pas crée socket\n");
        close(listenSOCKET);
        return 1;
    }
 
    serverADDRESS.sin_family = AF_INET;
    serverADDRESS.sin_addr.s_addr = htonl(INADDR_ANY);
    serverADDRESS.sin_port = htons(PORT);
 
    if (bind(listenSOCKET, (struct sockaddr *) &serverADDRESS, sizeof(serverADDRESS)) < 0) {
        printf("Peut pas trouver la socket\n");
        close(listenSOCKET);
        return 1;
    }
 
    listen(listenSOCKET, 5);
    clientADDRESSLENGTH[socketINDEX] = sizeof(clientADDRESS[socketINDEX]);
    int i=0;
    /*while(i<993199) {
    i++;*/
    while(1){
        connectSOCKET[socketINDEX] = accept(listenSOCKET, (struct sockaddr *) &clientADDRESS[socketINDEX], &clientADDRESSLENGTH[socketINDEX]);
        if (connectSOCKET[socketINDEX] < 0) {
            printf("Connection refusé\n");
            close(listenSOCKET);
            return 1;
        }
 
        pthread_create( &threads[socketINDEX], NULL, client, connectSOCKET[socketINDEX]);
        if(socketINDEX=4096) {
            socketINDEX = 0;
        } else {
        socketINDEX++;
        }
    }
    close(listenSOCKET);
}

Answers


Two problems:

  1. Your client sends a 4K block with the FBEGIN:filename:size header. The server attempts to read it in one 4K block. recv() can return less than a full buffer (as little as 1 byte).

  2. Your server doesn't close the file after reading it. This is probably causing the file size discrepancy (buffered data will get flushed when the file is closed).

Not a bug per se, but a performance issue: reading/writing/sending/receiving one byte at a time is S-L-O-W. You should do everything in larger blocks (even just 1K would be a huge perf boost). Just keep in mind the "recv() may complete partially" issue mentioned above.


Need Your Help

Getting the SQL from a Doctrine Migration

sql migration doctrine

I have been researching a way to get the SQL statements that are built by a generated Migration file. These extend Doctrine_Migration_Base. Essentially I would like to save the SQL as change scrip...

how to create restful web services using spring 3.0?

spring web-services rest

I searched for several approaches to create restful web services and finally narrowed my current requirement to learn how to create restful web services using spring.