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
Sleepis a WinAPI call. It expects milliseconds.I suspect you might have ported this to Linux by... lowercasing
Sleeptosleep. Howeversleeptakes 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
spawnwithout a context. This means it will default to a strand of the associated executor of the spawned function. There is none, sosystem_executoris 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_executordefaults 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_forcalls, use a waitable timer: Live On Coliru