Sending Files over socket not working properly

Hello there,

i am working on a project to send files over a chat socket using windows api.
My implementations of download() are:


ClientSide:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
void download(SOCKET &server, string filename, const int BUFF = 100000) {

    cout << "file: " << filename << "\n";

    FILE *readfp;
    size_t filesize;
    size_t numread, tmpnumread;
    size_t iters;
    int next = 1;
    unsigned exit_flag = false, exit_flag_server = false;


    if ((readfp = fopen64(filename.c_str(), "rb")) == nullptr) {
        exit_flag = true;
        send(server, (char *) &exit_flag, sizeof(exit_flag), 0);
        return; // error while opening
    }


    send(server, (char *) &exit_flag, sizeof(exit_flag), 0); // all right (flag == false)


    if (recv(server, (char *) &exit_flag_server, sizeof(exit_flag_server), 0); exit_flag_server) {
        cerr << "server error recognized\n";
        fclose(readfp);
        return;
    }

    // get file size
    _fseeki64(readfp, 0, SEEK_END);
    filesize = _ftelli64(readfp);

    _fseeki64(readfp, 0, SEEK_SET);

    iters = (filesize % BUFF == 0 ? (filesize / BUFF) : ((filesize / BUFF) + 1));

    cout << "iters: " << iters << "\n";

    //send(server, (const char *) &iters, sizeof(iters), 0);



    char *buffer = (char *) malloc(BUFF);

    while ((numread = fread(buffer, sizeof(char), BUFF, readfp)) > 0) {
        send(server, (char *) &numread, sizeof(numread), 0);

        recv(server, (char *) &numread, sizeof(numread), 0);

        send(server, buffer, numread * sizeof(char), 0);

        recv(server, (char *) &numread, sizeof(numread), 0);

    }





    fclose(readfp);
    free(buffer);
}



and ServerSide:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
void download(SOCKET &client, string filename, const int BUFF = 100000) {

    //cout << "file: \"" << filename << "\"";
    int next = 1;
    FILE *writefile;
    size_t filesize;
    size_t numread = BUFF;
    size_t iters{};
    unsigned exit_flag_client = false, exit_flag = false;

    if (recv(client, (char *) &exit_flag_client, sizeof(exit_flag_client), 0); exit_flag_client) {
        cerr << "client-side error\n";
        return;
    }


    if ((writefile = fopen64(filename.c_str(), "wb")) == nullptr) {
        cout << "error while opening \"" + filename + "\"\n";
        exit_flag = true;
        send(client, (char *) &exit_flag, sizeof(exit_flag), 0);
        return;
    }

    send(client, (char *) &exit_flag, sizeof(exit_flag), 0); // all right

    // get file size

    char *received_bytes = (char *) malloc(BUFF);

    //recv(client, (char *) &iters, sizeof(iters), 0);


    while (numread == BUFF) {
        recv(client, (char *) &numread, sizeof(numread), 0);


        send(client, (char *) &numread, sizeof(numread), 0);

        recv(client, received_bytes, numread, 0);

        fwrite(received_bytes, sizeof(char), numread, writefile);

        send(client, (char *) &numread, sizeof(numread), 0);
    }


    cout << "sucessfully received \"" << filename << "\"\n";
    fclose(writefile);
    free(received_bytes);

}



The problem is that I get errors, e.g. in the form that the server is no longer expecting data while the client is still sending it and buffer overflows.

Side quest:

Do i really need to send and receive alternating, or can i send multiple times in a row?

Can someone please help me to get my code work?

with nice greetings, Luke

Last edited on
There's a lot of chatter between the two, but they never exchange any actual data; just exit_flag and numread.

Your download() function is actuall an upload() function. And it should send the content of buffer, but it doesn't.

You can't just knock these things up without thinking about the exchange protocol.
1. What is exit_flag, and who cares?
2. What's the big deal of sending numread back and forth?
3. When are we going to get around to sending/receiving data?
Last edited on
Focus on getting basic send and receive working without all the error_flag handshaking.

The sender should send the file size once at the start.

send() can return before the whole buffer is sent.
recv() can return before the buffer is full.
So you typically need wrapper functions to make sure everything is as you expect.
This is especially true on sending.

For example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
ssize_t sender(SOCKET sock, char *buff, size_t size) {
    size_t sent = 0;
    ssize_t result = 0;
    do {
        result = send(sock, buff, size, 0);
        if ( result > 0 ) {
            // measure progress
            buff += result;
            size -= (size_t)result;
        } else if ( result == 0 ) {
            // remote disconnected
        } else {
            // error
            // if it's a non-blocking socket, check for
            // errno == EAGAIN or errno == EWOULDBLOCK
            // Do you wait here, or return?
            // Some other errors like EINTR may also need special care
            // Not to mention whatever else is specific to Windows
        }
    } while ( result > 0 );
    return result;
}


In any event, you ALWAYS need to pay attention to the return results of send() and recv(). Never blindly assume success when network programming.

And read https://beej.us/guide/bgnet/html//
Hello guys,

thank you so much.

I didn't consider to expect that send() might not send the whole buffer at once (the other way around with recv()).

I've just implemted your proposal (with a few small changes, which is not worth talking about) like this, like youve shown:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
namespace wrappers {
    ssize_t sender_wrapper(SOCKET &sock, char *buff, size_t size) {
        size_t sent = 0;
        ssize_t result = 0;

        do {
            result = send(sock, buff, size, 0);
            if (result > 0) {
                buff += result;
                size -= (size_t) result;
            } else if (result == 0) {
                // remote disconnected
            } else {
                // error
                // if it's a non-blocking socket, check for
                // errno == EAGAIN or errno == EWOULDBLOCK
                // Do you wait here, or return?
                // Some other errors like EINTR may also need special care
                // Not to mention whatever else is specific to Windows
            }
        } while (result > 0 && size > 0);
        return result;
    }
    ssize_t receive_wrapper(SOCKET &sock, char *buff, size_t size) {
        size_t recved = 0;
        ssize_t result = 0;

        do {
            result = recv(sock, buff, size, 0);
            cout << "rcved " << result << "\n";
            if (result > 0) {
                buff += result;
                size -= (size_t) result;
            } else if (result == 0) {
                // remote disconnected
            } else {
                // error
                // if it's a non-blocking socket, check for
                // errno == EAGAIN or errno == EWOULDBLOCK
                // Do you wait here, or return?
                // Some other errors like EINTR may also need special care
                // Not to mention whatever else is specific to Windows
            }
        } while (result > 0 && size > 0);

        return result;
    }
}


my code is now working wonderfully.

Thanks !!

Luke

Topic archived. No new replies allowed.