If the server starts after the connection cannot be reached.why? boost_1_73_0、Linux operating system
#include "boost/asio.hpp"
#include "boost/asio/spawn.hpp"
int main() {
boost::asio::io_context ctx;
auto ep = boost::asio::ip::tcp::endpoint(boost::asio::ip::make_address("127.0.0.1"), 1560);
bool isConnect = false;
bool isRun = false;
boost::asio::ip::tcp::socket socket(ctx);
while (true) {
if (!isConnect && !isRun) {
boost::asio::spawn([&](boost::asio::yield_context y) {
isRun = true;
boost::system::error_code ec;
socket.async_connect(ep, y[ec]);
if (ec) {
isRun = false;
socket.close();
printf("close\n");
} else {
isConnect = true;
printf("connect\n");
}
});
}
ctx.poll_one();
Sleep(1);
}
}
It works fine on windows. My post looks mostly code, so I added this sentence. Thank you so much
First Things First
Sleep
is a WinAPI call. It expects milliseconds.I suspect you might have ported this to Linux by... lowercasing
Sleep
tosleep
. Howeversleep
takes seconds. So you might be waiting 1000s each poll.Fixing that by not using any platform-specific calls but instead using standard library functions already seems to "work" on my machine:
Live On Coliru
Next: Choose Your Context!
You
spawn
without a context. This means it will default to a strand of the associated executor of the spawned function. There is none, sosystem_executor
is defaulted. You can see this by printing the effective executor from inside the coro:Which will print
With
spawn(ctx, ...)
you'd see instead:What it means is that
ctx.poll()
never runs anything related to your coro or socket, because they're in a different execution context.Why Did It Appear To Work?
It appeared to work above, because at least on Linux
system_executor
defaults to a thread pool which runs their threads in the background.This is scary, because it made your program multi-threaded without you knowing: You had potential data-races waiting to happen on all the shared objects, as well as the problem that the loads of the boolean flags could easily be optimized in such a way that a change would never be detected.
What's The Goal
However, it's unclear what the poll loop accomplishes, really. You can simplify a lot by just taking the spawn out of the loop, and replacing the loop with the much more robust
run()
/run_for()
:Live On Coliru
This works correctly and without multiple threads.
UPDATE: Retrying The Connection?
I had a sudden brainwave and realized that maybe you want to retry the connection UNTIL it succeeds. In that case you can just put the loop inside the coroutine:
Live On Coliru
With online demo:
Outputting:
Local demo for interactive output:
Async Sleep
To avoid blocking the io context with the
sleep_for
calls, use a waitable timer: Live On Coliru