1

I'm trying to send a jpg file from a client to a server using TCP. When the picture arrives to the server side I can't open it, besides the size of the picture received is higher than the one sent (sent = 880 bytes , received = 894 bytes). Any one of you have an idea of how to do solve this problem ? Here is my code :

client code :

static int send_server_image(SOCKET sock){

    int n = 0;
    int siz = 0;
    FILE *picture;
    char buf[50];
    char *s="";

    cout << "Getting image size" << endl;
    picture = fopen("C:\\Users\\n.b\\Desktop\\c++\\TCP\\tcp_client_image_pp\\test.jpg", "r"); 
    fseek(picture, 0, SEEK_END);
    siz = ftell(picture);
    cout << siz << endl; // Output 880

    cout << "Sending picture size to the server" << endl;
    sprintf(buf, "%d", siz);
    if((n = send(sock, buf, sizeof(buf), 0)) < 0)
    {
            perror("send_size()");
            exit(errno);
    }

    char Sbuf[siz];
    cout << "Sending the picture as byte array" << endl;
    fseek(picture, 0, SEEK_END);
    siz = ftell(picture);
    fseek(picture, 0, SEEK_SET); //Going to the beginning of the file

    while(!feof(picture)){
        fread(Sbuf, sizeof(char), sizeof(Sbuf), picture);
        if((n = send(sock, Sbuf, sizeof(Sbuf), 0)) < 0)
        {
            perror("send_size()");
            exit(errno);
        }
        memset(Sbuf, 0, sizeof(Sbuf));
    }
}

server code :

static int recv_client_image(SOCKET sock){

    int n = 0;

    cout << "Reading image size" << endl;
    char buf[50];
    int siz = 0;
    if ((n = recv(sock, buf, sizeof(buf), 0) <0)){
        perror("recv_size()");
        exit(errno);
    }
    siz = atoi(buf);
    cout << siz << endl; // 880 output

    char Rbuffer[siz];
    cout << "Reading image byte array" << endl;
    n = 0;
    if ((n = recv(sock, Rbuffer, sizeof(Rbuffer), 0)) < 0){
        perror("recv_size()");
        exit(errno);
    }

    cout << "Converting byte array to image" << endl;
    FILE *image;
    image = fopen("recu.jpg", "w");
    fwrite(Rbuffer, sizeof(char), sizeof(Rbuffer), image);
    fclose(image);
    cout << "done" << endl;

}

Thank you.

EngineerN
  • 133
  • 2
  • 11
  • Are both systems (sender/receiver) same endianness? Which endianness? How many bytes are received by the first recv call? Less than sizeof(buf)? Add more debug output or run in a debugger and provide more info. – Erik Alapää Nov 18 '15 at 15:34

2 Answers2

0

You are using Variable Length Arrays, which is not standard C++ (ref). Even if it is accepted by your compiler, you should avoid using sizeof on that.

And you have a problem in the while(!feof(picture)). You read siz bytes from the file without any error and without setting the eof flag. On second read, you read 0 bytes and set the flag but also send another buffer.

You should write instead:

while(!feof(picture)){
    n = fread(Sbuf, sizeof(char), siz, picture);
    if (n > 0) { /* only send what has been read */
        if((n = send(sock, Sbuf, siz, 0)) < 0) /* or (better?) send(sock, Sbuf, n, 0) */
        {
            perror("send_data()");
            exit(errno);
        }
    }
    /* memset(Sbuf, 0, sizeof(Sbuf)); useless for binary data */
}

Same in server part:

if ((n = recv(sock, Rbuffer, siz, 0)) < 0){
    perror("recv_size()");
    exit(errno);
}

cout << "Converting byte array to image" << endl;
FILE *image;
image = fopen("recu.jpg", "w");
fwrite(Rbuffer, sizeof(char), siz, image);
fclose(image);

And there is a last possibility of error, at least if you are on a platform that makes a difference between text and binary file like Windows is that you forget to open the files in binary mode, which could break the jpg image. Because on windows for a binary file, byte 0x10 is seen as the new line (\n') and written as 2 bytes 0x0d 0x10 (\r\n).

So you must open the input file in rb mode and the output file in wb mode.

Community
  • 1
  • 1
Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
  • What you say seems right but when I correct my code I still got the same problem... – EngineerN Nov 19 '15 at 08:30
  • @EngineerN: Above code **cannot** receive more than `siz` characters, and cannot write more... See my edit for another possible cause – Serge Ballesta Nov 19 '15 at 08:49
  • I found the problem. The files need to be opened in binary mode. Look at my answer below. Thank you for your help – EngineerN Nov 19 '15 at 08:52
  • @EngineerN: Looks like we found it at the same time :-) – Serge Ballesta Nov 19 '15 at 08:53
  • It should **certainly** be `send(sock, Sbuf, n, 0)`. And `fwrite(Rbuffer, sizeof(char), siz, image);` should be `fwrite(Rbuffer, sizeof(char), n, image);`. And this **must** be in a loop. You can't assume the whole thing got read in a single read. – user207421 Nov 19 '15 at 09:08
  • @EJP: OP uses fseek + ftell to get the size, so a single read and a single write are possible... even if it is weird practice. You are right I should have warned about it. – Serge Ballesta Nov 19 '15 at 09:16
0

Solved :

All the correction that Serge Ballesta were right. But the problem was in the way I was opening my files.

You need to open the file in binary mode ("rb" for reading, "wb" for writing), not the default text mode.

Client :

picture = fopen("C:\\Users\\n.b\\Desktop\\c++\\TCP\\tcp_client_image_pp\\test.jpg", "rb");

Server :

image = fopen("recu.jpg", "wb");

That was the main problem. Thank you.

EngineerN
  • 133
  • 2
  • 11