0

I'm trying to make a program which sends to the server a .txt file, modifies it's content and then sends the modified content back to the client in C++. I have managed to make the tcp/ip communication to work fine for simple string text messages, but when I try to send the content of a .txt file, it fails to do so.

Here's a snippet of my code: (

Client:

fstream file;
string fileName = "Test.txt";
string textToSend;
int sendResult;

file.open(fileName);

while (!file.eof())
{
    getline(file, textToSend);
    sendResult = send(sock, textToSend.c_str(), textToSend.size() + 1, 0);
}
string end_msg = "end";
sendResult = send(sock, end_msg.c_str(), end_msg.size() + 1 , 0);

file.close();

if (sendResult != SOCKET_ERROR)
{
    ZeroMemory(buf, 4096);

    int bytesReceived = recv(sock, buf, 4096, 0);

    if (bytesReceived > 0)
    {
        cout << "Server> " << string(buf, 0, bytesReceived) << endl;
    }
    else
    {
        cout << "Error on client - bytesReceived" << endl;
    }
}

// Gracefully close down everything
closesocket(sock);
WSACleanup();
}

Server:

// While loop: accept and echo message back to client
char buf[4096];

while (true)
{
    ZeroMemory(buf, 4096);

    // Wait for client to send data
    int bytesReceived = recv(clientSocket, buf, 4096, 0);

    if (bytesReceived == SOCKET_ERROR)
    {
        cerr << "Error in recv(). Quitting!" << endl;
        break;
    }
    else
    {
        if (bytesReceived == 0)
        {
            cout << "Client disconnected!" << endl;
            break;
        }
    }

    buf[bytesReceived] = '\0';
    while (buf != "end")
    {
        cout << buf << endl;
        bytesReceived = recv(clientSocket, buf, 4096, 0); //Here seems to be the problem in debug mode
        buf[bytesReceived] = '\0';
    }

    cout << string(buf, 0, bytesReceived) << endl;

    // Echo message back to client
    send(clientSocket, buf, bytesReceived + 1, 0);
}

// Close socket
closesocket(clientSocket);

// Shutdown Winsocket
WSACleanup();

}

Using debug mode, I noticed that in server side

bytesReceived = recv(clientSocket, buf, 4096, 0);

it can't get to the second row of my text file.

P.S. : I'm new to tcp/ip on c++, having basic experience on Java, Any help is great, thanks.

HolyBlackCat
  • 45,832
  • 5
  • 81
  • 134
Vlad
  • 35
  • 7
  • why do you send single lines and not the full contents of the file? – 463035818_is_not_a_number Feb 09 '18 at 15:51
  • send() and recv() are `streamed`. When you do `int bytesReceived = recv(clientSocket, buf, 4096, 0);` you are saying "try to recv 4096 bytes", but you may only get 1024 of those 4096, where your next recv may have the remaining bytes. Actually, I see multiple times where you make this mistake – Treyten Carey Feb 09 '18 at 15:53
  • please explain how you know that the code is broken. " it fails to do so" isnt a detailed problem description – 463035818_is_not_a_number Feb 09 '18 at 15:53
  • recv doesn't magically append to your buffer. You have to manage that yourself. –  Feb 09 '18 at 15:55
  • Possible duplicate of https://stackoverflow.com/questions/25634483/send-binary-file-over-tcp-ip-connection – Justin Randall Feb 09 '18 at 15:58
  • Never loop on `eof()` http://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-considered-wrong – Galik Feb 09 '18 at 15:58
  • 2
    What do you think happens here `while (buf != "end")` –  Feb 09 '18 at 15:58
  • @user463035818 : I researched on google but I found only people that sent the content line by line to the server. I assumed that there isn't a way to send all the file content to the server directly. – Vlad Feb 09 '18 at 16:01
  • @Treyten Carey : I don't understand. – Vlad Feb 09 '18 at 16:03
  • @user463035818 : What I want to do is to send a .txt file, to the server. I tried sending it line by line, but on the second line, the server part doesn't receive it. The first line it does. – Vlad Feb 09 '18 at 16:03
  • @Galik : can you please be more specific on why it shouldn't? – Vlad Feb 09 '18 at 16:03
  • @manni66 : I used that while instruction to iterate all file until the end – Vlad Feb 09 '18 at 16:04
  • I might be wrong, but I wouldnt be surprised if the only reason the examples you found send single lines is just for the sake of the example. Did you try to send all the contents at once? – 463035818_is_not_a_number Feb 09 '18 at 16:04
  • _I used that while instruction to iterate all file until the end_ no, you didn't. –  Feb 09 '18 at 16:04
  • 1
    @Vlad The link I posted provides a lot of detail. – Galik Feb 09 '18 at 16:05
  • @user463035818 : I'd like to know how to do it. I have never sent a file over tcp/ip. I don't want the code given, I want the explanation on how should I do it. – Vlad Feb 09 '18 at 16:05
  • simply read all the contents instead of using `getline` – 463035818_is_not_a_number Feb 09 '18 at 16:06
  • @Galik : I am reading it right now, thank you for posting it! – Vlad Feb 09 '18 at 16:06
  • @user463035818 : I will try this and post my feedback here. – Vlad Feb 09 '18 at 16:08
  • Running the Winsock Client and Server Code Sample: https://msdn.microsoft.com/en-us/library/windows/desktop/ms737889(v=vs.85).aspx – Robert Andrzejuk Feb 09 '18 at 16:27
  • @user463035818 : I have managed to get all content of file using : `ifstream file("Test.txt"); string content((istreambuf_iterator(file)), (istreambuf_iterator()));` – Vlad Feb 09 '18 at 16:32
  • If no error occurs, ```send``` returns the total number of bytes sent, which can be less than the number requested to be sent in the ```len``` parameter. Otherwise, a value of SOCKET_ERROR is returned, and a specific error code can be retrieved by calling WSAGetLastError. – Robert Andrzejuk Feb 09 '18 at 17:01

1 Answers1

2

Generally some kind of communication protocol needs to be defined to send and receive the data cleanly. Especially if You sending and recieving multiple messages.

Here the data is been sent and received both from the client and server without any consideration in which state is the other application.

I guess that maybe the client has closed down the connection and the server cannot send the reply so it doesn't continue to receive the next messages.

I have to guess because the whole code is not provided to reproduce.

You should do some debugging - checking in which state is ether application and what is going on inside the code. Use two IDE's - one for the server, one for the client.

Below is a simple client which sends it's information to the server, and the server just receives it.

If a more complicated scenario is needed then You have to think about how the client and server will agree between each other, how to know what to do next.


client and server code is according to MSDN: Running the Winsock Client and Server Code Sample

In the // Send an initial buffer the function should send the data and check how much data has already been sent.

Something like this:

std::ifstream file( "Test.txt" );
std::string   content( ( std::istreambuf_iterator< char >( file ) ),
                     ( std::istreambuf_iterator< char >() ) );


// Send an initial buffer
int bytes_to_send = content.length();
int bytes_sent    = 0;
do
{
    iResult = send( ConnectSocket, content.data() + bytes_sent, bytes_to_send, 0 );
    if ( iResult != SOCKET_ERROR )
    {
        bytes_to_send -= iResult;
        bytes_sent += iResult;
    }
} while ( iResult != SOCKET_ERROR && bytes_to_send > 0 );

On the recieving side the code also has to recieve in a loop like in the example:

// Receive until the peer shuts down the connection
do
{
    iResult = recv( ClientSocket, recvbuf, recvbuflen, 0 );
    if ( iResult > 0 )
    {
         //...

} while ( iResult > 0 );

I used a 2MB test file and the send command worked by sending in one shot all the data.

On the recieving end, the data was recieved in 512byte batches, which means there where many iterations of the loop.

Robert Andrzejuk
  • 4,637
  • 2
  • 20
  • 30
  • Thank you very much. I have managed to do something by myself and it's working, but I must admit that your solution is much more logical. To answer why I didn't put all the code: I wanted to do so, but the tools to format your code on stack overflow are horrible. I never understood it and I wasted 20 minutes on formulating my question just by trying to figure it out how to format my code :D. Thank you once again! – Vlad Feb 09 '18 at 20:56
  • For formatting code, I usually format in my IDE and add extra braces around the code, which gives me the extra spaces required before the code. After autoformat I copy it. You have to leave a line empty before and after the code. – Robert Andrzejuk Feb 09 '18 at 21:20