简体   繁体   中英

Formatting errors while transferring files over multiple clients using Sockets in C

I am trying to implement a simple code tester : a very basic version of the ACM ICPC or Google Code Jam online judger.

The evaluation part works (so far) but I'm stuck silly at the file transfer part.

Basically my setup is this :

I have a server (always on) and multiple client systems belonging to teams who'll submit their code. They may transfer files amongst one another within a team, but the server will keep a log of transfers. The server may sometimes send announcements to all or certain clients. The final code will be submitted to a particular empty client machine for evaluation.

Now, my server side code is having trouble. I'm using

select(fdmax+1, &read_fds, NULL, NULL, NULL)

to identify clients ready for writing data to me - I'm aware this polling can be done by fork() somehow but I'm neither sure nor comfortable about it.

For receiving the data to the server I'm using the following function :

void send_recv(int i, fd_set *master, int sockfd, int fdmax)
{
    int nbytes_recvd, j;
    char recv_buf[BUFSIZE], buf[BUFSIZE];

    if ((nbytes_recvd = recv(i, recv_buf, BUFSIZE, 0)) <= 0) {
        if (nbytes_recvd == 0) {
            printf("socket %d hung up\n", i);
        }else {
            perror("recv");
        }
        close(i);
        FD_CLR(i, master);
    }else {
        FILE *logger;
        logger = fopen(fname2, "w");
        fprintf(logger,"Client %i> %s", i,recv_buf);
        for(j = 0; j <= fdmax; j++){
            send_to_all(j, i, sockfd, nbytes_recvd, recv_buf, master );
        }
    }
}

Here, instead of logging all file data being transferred over the stream separately, I'm getting a jumbled mess that is hard to parse.

This function is actually transferring the files (all ANSI *.c) :

void send_to_all(int j, int i, int sockfd, int nbytes_recvd, char *recv_buf, fd_set *master)
{
    if (FD_ISSET(j, master)){
        if (j != sockfd && j != i) {    //prevents data rewrite to incoming host
            int client;
            sscanf(recv_buf, "%d >", &client);
            if(client == 0){                //universal send
                if (send(j, recv_buf, nbytes_recvd, 0) == -1) {
                    perror("send");
                }
            }                               //send to specified host
            else if (send(client, recv_buf, nbytes_recvd, 0) == -1) {
                perror("send");
            }
        }
    }
}

Here the incoming files lose all their formatting and gets printed twice every time.

A stripped down version of my server code is here : http://codepad.org/TTejTfbL

My question is, am I doing something fundamentally wrong ? Is my logic (and, by extension, my code) irretrievably broken ?

I'd be gratified if someone could point me in the right direction. Or even tell me to throw it all away and start from scratch. (^;__;^)

You can't assume that you can send() any amount of data in a single call, and have it monotlithically succeed or fail. There are limits to the buffers implemented by the library.

It's perfectly possible for you to pass eg 20 KB to send() , and have it successfully return after sending only 4,711 bytes. That would require you to step forward in your buffer by the proper amount, decrease the "bytes to go", and try again.

This needs to be looped until you've sent all your data, or received an I/O error from the socket.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM