etaiso
etaiso

Reputation: 2746

sending whole data at once using socket

I'm trying to send a file from client to server using winsock2 lib.

After converting the file into char array, i'm sending this array using the send() command.

The problem: the data sent separately.

For e.g: I have file of size: 144429. It does not send it at once, the data is split into many portions, like: first send: 1460

second send: 21544

third send: 57136

etc..

until to whole data is sent.

so my question is: what causes it to send it by parts and not by once????

Solution I found working but not making any sense: If i'm adding

cout << "bla bla bla";

before the send() function, it does work and send the whole 144429 by once. (but if the string given to cout is shorter, no change, send by parts)

CODE:

CLIENT SIDE

int Client::sendData(char *sendbuf, int length)
{   
    int iResult;

    // if I remove those next few lines (until and including the cout line)
    // the send will split.
    char tmp[1];
    // sent 1 dummy byte
    iResult = send( _connectSocket, tmp, 1, 0 );
    if (iResult == SOCKET_ERROR) {
        printf("send failed with error: %d\n", WSAGetLastError());
        return closeSocket();
    }
    cout << "SENDING DATA..." << endl;

    // THIS IS THE RELEVANT AND ACTUAL DATA I WANT TO SEND
    // send the data
    iResult = send( _connectSocket, sendbuf, length, 0 );
    if (iResult == SOCKET_ERROR) {
        printf("send failed with error: %d\n", WSAGetLastError());
        return closeSocket();
    }

    cout << "Data sent (" << iResult << " Bytes)" << endl;

    return 0;

}

SERVER SIDE:

    char recvbuf[DEFAULT_BUFLEN];
int recvbuflen = DEFAULT_BUFLEN;
int iResult = 0;
int totalBytesRead = 0;

// Receive until the peer shuts down the connection
do {
    totalBytesRead += iResult;
    iResult = recv(_clientSocket, recvbuf, recvbuflen, 0);
    if (iResult > 0) {
        printf("RECEIVED DATA\n");
        printf("Bytes received: %d\n", iResult);

    } else if (iResult == 0)
        printf("Connection closing...\n");
    else {
        printf("recv failed: %d\n", WSAGetLastError());
        closesocket(_clientSocket);
        WSACleanup();
        return 1;
    }

} while (iResult > 0);

// store data into file
FileTransfer::binaryToFile(recvbuf, "doch.docx", totalBytesRead-1);

return 0;

}

Upvotes: 0

Views: 1294

Answers (2)

Mats Petersson
Mats Petersson

Reputation: 129524

There is no way to guarantee that send transmits some data as one unit - it just doesn't work that way. You have to add some extra information to tell the system that "Here's this much data to come" and/or "I'm done now". Even if you could convince your sending side to send of everything in one packet, assuming the receiving side isn't connected DIRECTLY with just a simple cable to the sender, you can't guarantee that the packet isn't broken up during it's passing through the network.

You just have to accept that if you are sending more than a single byte in a packet, you may have to call send multiple times. To simplify it, write a function that takes a an arbitrary size "whole packet" and calls send as many times as necessary... If you have a protocol that indicates the size of the data sent [such as in the first few bytes], you could have a receive function that does the same thing.

Upvotes: 3

mikyra
mikyra

Reputation: 10377

Depending on the socket type you are using there might be a limitation of data size in the underlying transport protocol.

In case you are using a network socket the size is limited by the maximum transfer unit (see: http://en.wikipedia.org/wiki/Maximum_transmission_unit).

If your data doesn't fit this size you will have to iterate in a loop sending portions of your data until either an error occurs or all data has been sent.

Upvotes: 2

Related Questions