multiple asio::async_write at the same time?

I'm using a tcp stream to reliably send messages, so I need each call to asio::async_write to finish before the next one starts.

I've discovered that simply creating a strand and using it to wrap calls to asio::async_write doesn't do the trick.
In other words multiple calls to asio::async_write will result in mixing of those messages.

Do I have to construct a messaging queue for storing those messages until the handlers for previous ones are called or is there a built in alternative?
as async_write documentation says, "The program must ensure that the stream performs no other write operations (such as async_write, the stream's async_write_some function, or any other composed operations that perform writes) until this operation completes."

I had an application where the source of messages to send over TCP was asynchronous, and so indeed I wrote a message queue, from which the async_write's completion handler would grab the next message to call the next async_write with (it was before yield), that seems reasonable.
I'm assuming you're mentioning yield because it could be useful here?
I'm assuming you're mentioning yield because it could be useful here?

It doesn't change the semantics, it just makes async code look sane (and future-proof)
Could you show me how and why to use it?
zoran404 wrote:
Could you show me how and why to use it?

Why - to escape the callback hell. How - boost has examples.

There are actually two kinds of coroutines there: stackful and stackless. Personally I like stackless (and that's where C++ moving too), but here's a stackful demo showing your multiple async writes, because it's better documented:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <string>
#include <vector>
#include <boost/asio.hpp>
#include <boost/asio/spawn.hpp>
std::vector<std::string> v{"foo\r\n", "bar\r\n", "baz\r\n", "xyzzy\r\n"};
int main()
{
  boost::asio::io_service io;
  boost::asio::spawn(io, [&](boost::asio::yield_context yield) {
  try {
    boost::asio::ip::tcp::endpoint ep(boost::asio::ip::address::from_string("127.0.0.1"), 12645);
    boost::asio::ip::tcp::socket sock(io);
    sock.async_connect(ep, yield);
    for (auto& str: v)
        boost::asio::async_write(sock, boost::asio::buffer(str), yield);
  } catch (std::exception& e) {
     std::cout << "caught " << e.what() << '\n';
  }
  });
  io.run();
}


to test, netcat in another terminal:
1
2
3
4
5
$ nc -l 12645
foo
bar
baz
xyzzy
Last edited on
I can avoid callback simply by using spawn and passing yield instead? Damn that's nice.

Too bad I'm writing a server and instantiating a thread for each connection isn't practical.

Thanks for the example though!
You can also do that by using reenter and the pseudo-keyword yield: there's a demo of that approach in "http server v4" in boost docs: http://www.boost.org/doc/libs/1_63_0/doc/html/boost_asio/example/cpp03/http/server4/server.cpp

How are threads relevant? spawn doesn't create any.
Ok, I didn't notice that spawn doesn't create threads when I wrote that.
Either way I've already finished my server with the callbacks.
I would like to switch to coroutines though, simply because it's easier to write.
Not sure if there's any performance overhead to this?
CAN SOMEBODY HELP ME WITH THIS ?

Write a program that inputs a time from the console. The time should be in
the format "HH:MM AM" or "HH:MM PM". Hours may be one or two digits, for
example, "1:10 AM" or "11:30 PM". Your program should include a function
that takes a string parameter containing the time. This function should
convert the time into a four-digit military time based on a 24-hour clock.
For example, "1:10 AM" would output "0110 hours", "11:30 PM" would
output "2330 hours", and "12:15 AM" would output "0015 hours". The
function may either write the time to the console or return a string to be
written to the console by the main function.

#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;

string convertToMilitaryTime(string time)
{
//gets colon and space position in the
// given time string
int colon = time.find(':');
int space = time.find(' ');

//extracts hours, minutes and meredian strings from the
// input time string
string hh = time.substr(0, colon);
string mm = time.substr(colon+1, space-colon-1);
string mer = time.substr(space+1);

//converts hours from string format to integer
int hours = atoi(hh.c_str());

// updating hours based on meredian
if(mer == "PM" &&hours != 12)
hours = hours + 12;
else if ( mer == "AM" &&hours == 12)
hours = 0;

//placing leading zero in hours if hour is one digit
if( hours >= 0 &&hours <= 9)
hh = "0";
else
hh = "";

//converring modified hours to string format
char H[5];
hh += itoa(hours,H,10) ;

//returns required output string
return hh + mm + " hours";
}

// main function
int main()
{
// inputs time in the form hh:mm AM/PM
string time;
cout << "Enter time (HH:MM AM) or (HH:MM PM): ";
getline(cin,time,'n');

//calls convertToMilitaryTime to conevert the given
//time into military time

string milTime = convertToMilitaryTime(time);

//displays to the console
cout << milTime << endl;
return 0;
}
Topic archived. No new replies allowed.