0

I am using Linux. C2 (client) should read and send contents of file F1.txt to C1 (server) in successive messages of size 256 bytes (or remaining size of the file when you get near the end of the file)

First, I get the F1.txt size in bytes and sent it to the server c1.

fseek(fp, 0L, SEEK_END);  //move fp to the end of the file
    int fileLen =  ftell(fp);  // get the file size because ftell returns the current value of the position indicator
    fseek(fp, 0L, SEEK_SET); //seek back to the begin of the file
    write(sock, &fileLen, sizeof(int));   //send file size to server c1 

Next, I send the file in successive 256 bytes by a for loop. The client c2 code is

    char buffer[BUF_SIZE] = {0};  //BUF_SIZE=256
    for (int i = 0; i <((fileLen/256) +1); i++)
    {
        memset(buffer, 0, sizeof(buffer));  //clear buffer
        fread(buffer, 1, i <(fileLen/256)?(sizeof(buffer)):(fileLen%256), fp);  // read BUF_SIZE elements, each one with a size of 1 bytes,
        printf("Message client_c2 sent: %s\n", buffer);
        write(sock, buffer,  i <(fileLen/256)?sizeof(buffer):(fileLen%256));
        usleep(1000);
    }
    fclose(fp);

The server c1 read the filesize, and read the socket within the for loop:

    int receiveFileLen; 
    read(clnt_sock, &receiveFileLen, sizeof(int));
    printf("clinet_c2 file size is %d\n",receiveFileLen);
    for (int i = 0; i < ((receiveFileLen/256) +1); i++)
    {
        memset(buffer, 0, sizeof(buffer));  //clear buffer
        read(clnt_sock, buffer, i < (receiveFileLen/256) ? sizeof(buffer) :(receiveFileLen%256)  );
        printf("buffer that writen into file is %s\n",buffer);
        fwrite(buffer, strlen(buffer), 1,fp);

    }

(1) The problem is in client c2 code's fread(fp), when i printf("Message client_c2 sent: %s\n", buffer); I found every time at the end of buffer, there is a wrong char (square shape in which shows 0002.)

(2) In server c1 code. I read the socket and fwrite it to a local txt. fwrite(buffer, strlen(buffer), 1,fp); I tried strlen(buffer)+1, but it gives me wrong chars ^B in the txt, so I use strlen(buffer).

(3) In server c1 code, I cannot read the full content of the remaining size of the file when I get near the end of the file. In the for loop, I get the previous iterations correctly written into txt, but when comes to the last iteration, i = (receiveFileLen/256) in other words, only part of socket content is read and fwrite into the txt, there is still chars that should be read remaining in the socket.

Thank you for your help!

MikeCAT
  • 73,922
  • 11
  • 45
  • 70
yeehaw
  • 159
  • 2
  • 11
  • 3
    The first problem that leaps out is that you aren't checking the return-values of any of your `fread()`, `read()`, `fwrite()`, or `write()` calls, which means you don't know how many bytes were actually read or written. Any of those calls may fail, or only partially succeed (writing/reading only the first portion of the bytes you passed in), and your code needs to handle those cases properly or it won't transfer the data correctly. – Jeremy Friesner Feb 20 '21 at 05:50
  • 3
    Do you understand that C-strings are null-terminated? And that `buffer` is not? And what happens if you try to `printf` an improperly terminated string? – Beta Feb 20 '21 at 05:52
  • @Beta do you mean I should pritnf use for loop %c instead of %s? Even though I misused printf, this should not have any influence on my next socket part, right? – yeehaw Feb 20 '21 at 05:55
  • 4
    Your code is full of all the usual bugs, assumptions, misconceptions and mishandling associated wth TCP transfers. Just to start with, you assume that 'int' has the same size at both ends. – Martin James Feb 20 '21 at 06:43
  • 2
    Until you fix the issues raised by Jeremy and beta, and then retest, there is no point in investigating further. – Martin James Feb 20 '21 at 06:45
  • @JeremyFriesner Thanks for your suggestion. I tried to return the value of write() of sender client c2, and read() of receiver server c1. Like I said in (3), error happens when comes to the last iteration of for read loop. the `int readNum = read(clnt_sock, buffer, i < (receiveFileLen/256) ? sizeof(buffer) :(receiveFileLen%256) );` of server c1 failed to read the `(receiveFileLen%256) ` bytes from the socket, though from `int writeNum = write(sock, buffer, i <(fileLen/256)?sizeof(buffer):(fileLen%256)); ` I know I have successfully write `fileLen%256` into the socket. – yeehaw Feb 20 '21 at 07:54
  • @JeremyFriesner Take my F1.txt as an example, the successive messages of size 256 bytes has been correctly write() and read() in the socket, but when I write() the remaining 209 bytes to the socket, I know the remaining 209 bytes has been successfully sent to the socket, but read() can only read 168 bytes, though I told it to read 209 bytes. I think I have located the problem, but don't understand why read() fails to read the exact number I told it and there are 209 bytes in the socket. When I call read() one more time, there are still bytes in the socket it can read (209-168) bytes in there – yeehaw Feb 20 '21 at 07:59
  • @Beta I am now aware that printf(%s) may add \0 at the end of my char array, as a result my array is one byte smaller. I won't define it like `char buffer[BUF_SIZE];` , but using `char buffer[BUF_SIZE];` or `char buffer[BUF_SIZE] = "";`, I can get printf work correctly, but I just wanted to use print for debug, so the problem is still related to why write() has correctly written 209 bytes into socket, but read() can only read 168 bytes while leaving remaining bytes in the socket. As stated in (3) – yeehaw Feb 20 '21 at 08:10
  • 1
    I wouldn't print it as char/string, but as a sequence of hex values using %02x on each element in a for loop. This is probably overkill unless you're really stumped, because, like the other commenters said, it's probably best to track the responses from the read/write functions so you can track true byte counts. Your last write is going to be messed up, because you're always writing out sizeof(buffer) instead of how many bytes you really read. Actually, you're using strlen, which is found by looking for the first 0x00! That could end up being huge or too small if a 0x00 is in your data! – Mark H Feb 20 '21 at 09:11
  • 1
    @yeehaw that is how read() and recv() work; if they have bytes to give you, they give you the bytes that they have, which may be less than the number of bytes you asked for. If you want to fill up your entire buffer you will need to make a loop that calls read() repeatedly, or alternatively call recv() with the MSG_WAITALL, but even then you’ll need to deal with short reads on EOF, or if a signal is received during the call. – Jeremy Friesner Feb 20 '21 at 15:03
  • @JeremyFriesner Problems are solved! I now know that read() may not read all the bytes i told it in one shot, so I need a while loop to read. My first and second questions are related to using char array to represent a "", so I dont need to use strlen()+1, because there is no \0 in the end of my char array. I want to answer by myself, but I dont have enough points LOL ~ [link](https://stackoverflow.com/questions/1251392/read-from-socket-is-it-guaranteed-to-at-least-get-x-bytes) similar question has already been asked – yeehaw Feb 20 '21 at 21:11
  • @MarkH Thank you! I think since I use `fwrite(buffer, strlen(buffer), 1,fp);` while my buffer is a char array, this is not correct to use `strlen(buffer)+1`. I was not clear about the difference between c-string and char array like Beta said. All solved! – yeehaw Feb 20 '21 at 21:14
  • Could anyone give my question a thumbs up so that I can 50 points to comment, thank you :) – yeehaw Mar 08 '21 at 07:39

0 Answers0