6
votes

Creating a simple TCP server based on examples but still do not get how to create a socket that would read some amount of bytes and if there will not be enough would wait. I need this to be NOT asynchronous operation.

#include <iostream>
#include <boost/asio.hpp>

#ifdef _WIN32
#include "Windows.h"
#endif

using namespace boost::asio::ip;
using namespace std;

int main(){
    int m_nPort = 12345;
    boost::asio::io_service io_service;
    tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), m_nPort));

    cout << "Waiting for connection..." << endl;

    tcp::socket socket(io_service);
    acceptor.accept(socket);
    cout << "connection accepted" << endl;
    try
    {
        socket.send(boost::asio::buffer("Start sending me data\r\n"));
    }
    catch(exception &e)
    {
        cerr << e.what() << endl; //"The parameter is incorrect" exception
    }
}

How to receive 10000 bytes and do it either until all 10000 arrive OR 1000 millisecond timeout and throw an exception?

2
that's interesting. I've found this question which asks how to set up a timer so it doesn't block: stackoverflow.com/questions/291871/…Karoly Horvath
Why the no asynchronous requirement?Sam Miller

2 Answers

6
votes

Boost 1.47.0 just introduced a timeout feature for basic_socket_iostream, namely, the expires_at and expires_from_now methods.

Here's an example based on your snippet:

#include <iostream>
#include <boost/asio.hpp>

using namespace boost::asio::ip;
using namespace std;

int main(){
    int m_nPort = 12345;
    boost::asio::io_service io_service;
    tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), m_nPort));

    cout << "Waiting for connection..." << endl;

    tcp::iostream stream;
    acceptor.accept(*stream.rdbuf());
    cout << "Connection accepted" << endl;
    try
    {
        stream << "Start sending me data\r\n";

        // Set timeout in 5 seconds from now
        stream.expires_from_now(boost::posix_time::seconds(5));

        // Try to read 12 bytes before timeout
        char buffer[12];
        stream.read(buffer, 12);

        // Print buffer if fully received
        if (stream) // false if read timed out or other error
        {
            cout.write(buffer, 12);
            cout << endl;
        }
    }
    catch(exception &e)
    {
        cerr << e.what() << endl;
    }
}

This program works for me on Linux.

Please note that I'm not advocating that you use timeouts instead of asynchronous operation with a deadline timer. It's up to you to decide. I just wanted to show that timeouts are possible with basic_socket_iostream.

0
votes

How to timeout and throw an exception?

Generally speaking, you only get timeouts and cancelability when using asynchronous methods. There are some platform specific ways around this, which have been discussed on SO in previous questions. I strongly suggest you investigate using asynchronous methods, it will make understanding the logic much easier.

That said, you can present a synchronous interface by using asynchronous methods underneath. This is done in the blocking TCP client timeout example provided by the Asio library. Beware however, the example isn't entirely straightforward (albeit, well commented) due to its inversion of control and use of lambda functions. I suggest you investigate using asynchronous methods directly prior to attempting something like this.

How to receive 10000 bytes?

use the async_read free function, the remarks section describes exactly what you need

Remarks

This overload is equivalent to calling:

boost::asio::async_read(
    s, buffers,
    boost::asio::transfer_all(),
    handler);

where your buffer is 10,000 bytes in size.