0

I have a problem that I'm hoping is a mistake as I am a bit new to linux C.

I have a server, that sends a file to a client. The code works perfectly fine over a wired connection, 100% success rate every time. However, when I try to run that same code over a 3G USB connection at -65dB (Strong), the client will usually only receive the first 1 or 2 thousand bytes of the file. (Forgive the syntax errors won't let me space properly)

        // CLIENT CODE

        char* fs_name = "/target/to/send";
        char sdbuf[LENGTH]; // Send buffer, LENGTH == 512
        printf("Sending %s to the Client... \n", fs_name);
        FILE *fs = fopen(fs_name, "r");
        if(fs == NULL)
        {
            fprintf(stderr, "ERROR: File %s not found on server. (errno = %d)\n", fs_name, errno);
            exit(1);
        }

        bzero(sdbuf, LENGTH); 
        int fs_block_sz; 
        while((fs_block_sz = fread(sdbuf, sizeof(char), LENGTH, fs))>0)
        {
            if(send(client, sdbuf, fs_block_sz, 0) < 0)
            {
                fprintf(stderr, "ERROR: Failed to send file %s. (errno = %d)\n", fs_name, errno);
                exit(1);
            }
            bzero(sdbuf, LENGTH);
        }
        printf("File send Success\n");



            // SERVER CODE

        char* fr_name = "/home/file/to/save";

        FILE *fr = fopen(fr_name, "a");

        if(fr == NULL)

            printf("File %s Cannot be opened.\n", fr_name);

        else
        {
                // zero out bytes
            bzero(revbuf, LENGTH); 

            int fr_block_sz = 0;

            while((fr_block_sz = recv(sd, revbuf, LENGTH, 0)) > 0)  //LENGTH == 512
            {
            int write_sz = fwrite(revbuf, sizeof(char), fr_block_sz, fr);

                if(write_sz < fr_block_sz)
            {
                    error("File write failed.\n");
                }
            bzero(revbuf, LENGTH);
            if (fr_block_sz == 0 || fr_block_sz != 512) 
            {
            break;
            }
        }

                // error checking
        if(fr_block_sz < 0)
                {
        if (errno == EAGAIN)
        {
            printf("recv() timed out.\n");
        }
        else
        {
            fprintf(stderr, "recv() failed due to errno = %d\n", errno);
        }


            fclose(fr);

If anyone out there could shed some light on what I'm doing wrong I would be most appreciative. Thanks for reading.

EDIT: The server is Ubuntu 10.04 and the client is Arch Linux ARM and the type of file being sent is an ARM binary.

4r4r4r
  • 3
  • 3
  • Why client(according to your code server) recieve only 1000 bytes, what recv return at exit of cycle? if rect return < 0 what print fprintf(stderr, "recv return error: %s\n", sterror(errno))? – fghj Jul 06 '13 at 00:09
  • If I understand correctly what you mean, the client receives no error. The client simply saves the file as if it were the full thing and gives no error message, nor does the server. I then have to manually size that file to find that the xfer failed. It does work sometimes, maybe 15% of the time though. Perhaps I need to be sending the file in 1000 byte chunks and reassemble it on the client or something? I noticed 3G is a bit different than the wire, unfortunately. – 4r4r4r Jul 06 '13 at 00:27
  • You talk about some kind of magic. If you have TCP connection and from one side you send 100MB file chunk by chunk on another side you recieve or 100MB or broken connection. May be you use UDP? – fghj Jul 06 '13 at 00:36

1 Answers1

0

I think your main problem is here in your code labeled server but which really looks to be the client. You assume that the recv is going to get all 512 bytes on each recv but that's not true - you can and will get short reads. A little below you break out of the read loop if you haven't read exactly LENGTH (i.e. 512). That explains why your pgm quits after a couple of thousand bytes.

    while ((fr_block_sz = recv(sd, revbuf, LENGTH, 0)) > 0)  //LENGTH == 512
    {
        int write_sz = fwrite(revbuf, sizeof(char), fr_block_sz, fr);

        if (write_sz < fr_block_sz)
        {
            error("File write failed.\n");
        }

        bzero(revbuf, LENGTH);

        if (fr_block_sz == 0 || fr_block_sz != 512)
        {
            break;
        }

    }

You want something more like this:

    while ((fr_block_sz = recv(sd, revbuf, LENGTH, 0)) > 0)  //LENGTH == 512
    {
        if (fr_block_sz < 0)
            if (errno == EAGAIN)
               continue;
            else
               error;

        if (fr_block_sz == 0)
            break; //done

        int write_sz = fwrite(revbuf, sizeof(char), fr_block_sz, fr);

        if (write_sz < fr_block_sz)
        {
            error("File write failed.\n");
        }

        bzero(revbuf, LENGTH);
    }
Duck
  • 26,924
  • 5
  • 64
  • 92
  • Thank you Duck, but I don't understand. Have I confused server code w/client, and my server is really the client, and the code you posted is what my server should look like, or client? – 4r4r4r Jul 06 '13 at 00:43
  • Well server/client/whatever. That isn't important here. The above code comes directly from what you posted. I'll post some pseudo code for what I think should resolve your main problem. – Duck Jul 06 '13 at 00:56
  • Thanks Duck, I was able to make those changes on the client side based on your pseudo code (left the server the same) and that gave me a success rate of 5/7, the other transfers got to about 4K bytes. The 2 failed attempts might have been due to 3G connectivity though. Odd how it works fine over the wire though. I wonder if 3G programming techniques differ from traditional wire programming. – 4r4r4r Jul 06 '13 at 04:30