I have a program that uses Boost.Asio to connect to a server on localhost. Here is the relevant part of the code:
TcpClient::TcpClient(uint16_t port_number) : socket_(service_)
{
boost::asio::ip::tcp::resolver resolver(service_);
boost::asio::ip::tcp::resolver::query resolver_query("localhost", std::to_string(port_number));
auto endpoint_iterator = resolver.resolve(resolver_query);
boost::asio::connect(socket_, endpoint_iterator);
}
The code functions just fine. On Ubuntu, the connect function returns almost immediately. However, on Windows it takes over 2 seconds to complete.
Stepping through the boost code, I found the 2 seconds are spent on the Winsock connect function call.
Am I missing something (either in code, or in the environment) that can speed up this call?
Thank you!
If you have IPv6 enabled then resolver_query("localhost", std::to_string(port_number)); will return an IPv4 and IPv6 address (from experience with the IPv6 listed first). If your server isn't listening on IPv6 then boost::asio::connect will try IPv6 first, wait for it to fail and only then try IPv4.
Either get your server to listen on IPv6, use "127.0.0.1" instead of localhost or restrict the resolver to only return IPv4:
resolver_query(boost::asio::ip::tcp::v4(), "localhost", std::to_string(port_number));
Related
When I'm working on a UDP server I usually set the socket to listen on specified port and accept any IP. Keep in mind that sync receive works properly here.
std::unique_ptr<boost::asio::ip::udp::socket> socketUDP;
socketUDP.reset(new udp::socket(io_serviceUDP, udp::endpoint(udp::v4(), 9999)));
However, I would really like to have 2 different server applications listening at the same port (9999) but accepting only a single IP (I already know that IP). Each of the apps has its own client with its own IP.
But for some reason the following doesn't work (not receiving any packets in the app, while Wireshark can see it)
socketUDP.reset(new udp::socket(m_io_serviceUDP, udp::endpoint(asio::ip::address::from_string("169.254.1.2"), 9999)));
Please note :
1) According to the answer for : Issue with broadcast using Boost.Asio this should actually work. Of course my understanding isn't quite correct as I'm missing something
2) The provided IP is valid, works, sends data(confirmed by wireshark) and can be pinged
The issue is that your socketUDP's are not configured with:
set_option(boost::asio::ip::udp::socket::reuse_address(true));
However, simply calling the line above on your sockets won't work, because you must call reuse_address before the socket is bound to an endpoint... But you're constructing udp::socket with an endpoint which opens it and binds it to the endpoint, see basic_datagram_socket.
The solution is to call the constructor which just takes an io_service; open it, set the reuse_addressoption and then bind it, e.g.:
// construct the socket
boost::asio::ip::udp::socket socket_(io_service_);
// open it
boost::asio::ip::udp::endpoint rx_endpoint_(udp::v4(), 9999);
socket_.open(rx_endpoint_.protocol(), error);
if (error)
return false;
// then set it for reuse and bind it
socket_.set_option(boost::asio::ip::udp::socket::reuse_address(true));
socket_.bind(rx_endpoint_, error);
if (error)
return false;
// set multicast group, etc.
socket_.set_option(boost::asio::ip::multicast::join_group(ip_address));
...
I'm using the boost::asio library.
I've been trying to run my server on port 80, but can't get it to do so. Below is the culpable line in my code, with outcomes in the comments:
// This runs fine, and the webpage is visible on localhost:8000
tcp::acceptor a(*io_service, tcp::endpoint(tcp::v4(), 8000));
// This throws an error (at this line)
tcp::acceptor a(*io_service, tcp::endpoint(tcp::v4(), 80));
// This runs fine, but the webpage is NOT visible on localhost or localhost:80
tcp::acceptor a(*io_service, tcp::endpoint());
I've noticed that endpoint only accepts four-digit port numbers. Could this have something to do with it?
How can I see my page running on port 80? Thanks!
I am not sure how it works on Windows, but on Unix, including Linux, ports below 1024 can only be bound by privileged processes. Try running it as root. Of course you should give up the permissions (using setuid system call) after opening the port.
On my computer(Surface Pro 2), there is only one network adapter,
it is a wireless LAN adapter.
I worked on a small C++ project, it uses boost::asio to connect to
localhost and do its work, everything is just fine.
But today I found that if I disconnect the WLAN from the Internet,
this program does not work.
An exception will be thrown by resolver of boost::asio :
tcp::resolver::query query("localhost", "10127");
tcp::resolver resolver(io_service_);
tcp::resolver::iterator iterator;
try {
iterator = resolver.resolve(query);
}
catch (boost::system::system_error& e) {
log(e.what());
}
And the error message was: the requested name is valid but no data
of the requested type was found.
Ping to localhost is OK.
I feel puzzled, does a local network program need Internet ?
Does a local network program need a LAN adapter ?
Why ping works fine ?
I just had the same problem on a linux machine and looked up the boost asio documentation. You just need to add a flag argument to the query constructor:
tcp::resolver::query query("localhost","10127",tcp::resolver::query::canonical_name);
Note: the full scoped name of query is boost::asio::ip::tcp::resolver::query.
This happens because the default flags argument passed here is boost::asio::ip::tcp::resolver::query::address_configured, which means that the call should only resolve IPv4/IPv6 addresses if a non-loopback IPv4/IPv6 address is configured for the system.
I have no explanation of why you have this error. However, what I did in a project was not by specifying the port number directly, but rather by constructing the endpoint instance in two steps. I don't recall the rationale at the time for doing it this way, but it might help you.
My proposed solution is something like this:
ip::tcp::resolver::query query(ip::tcp::v4(), "localhost", ""); // empty service name
tcp::resolver::iterator it_endpoint = resolver.resolve(query);
ip::tcp::endpoint endpoint(ip::tcp::endpoint(*it_endpoint).address(), port);
This is a summarized excerpt of what I did, so it may not compile as-is.
local network does not required internet to work. In your case, I don't know exact the problem of Windows TCP/IP layer with resolve localhost when it does not have any DNS server config(Network card is not connected, ..etc). But you can use tcp::resolver::query query("127.0.0.1", "10127"); instead of tcp::resolver::query query("localhost", "10127");
which works always.
I have a third party library that acts as a HTTP server. I pass it an address and port, which it then uses to listen for incoming connections. This library listens in such a way that it doesn't receive exclusive usage of the port and address it's bound to. As a result, I can listen on the same port multiple times.
I need to run multiple instances of this HTTP server in the same process. Each instance has a default port, but if that port isn't available, it should use the next available port. This is where my problem is; I can end up with two HTTP servers listening on the same port.
I cannot change the HTTP server's code and the HTTP server will not alert me if it cannot listen on the port I give it, so I have to be able to check if a port is already in use before starting each HTTP server. I have tried checking if a port is already being listened on by binding my own socket with SO_REUSEADDR set to FALSE and SO_EXCLUSIVEADDRUSE set to TRUE, but the bind and listen calls both succeed when an existing HTTP server is already listening on that port.
How is this HTTP server achieving this effect, and how can I accurately check if a port is being listened on in this manner?
The quick and dirty method would be to try to connect() to the port on localhost. If the connect() call succeeds, then you know the port is currently being listened on (by whomever received the connection). If the connect call fails (in particular with ECONNREFUSED) then you can be pretty sure that nobody is listening on that port.
Of course, there's a race condition here: Nothing is really stopping another program from swooping in and grabbing the port immediately after you ran the above test, but before you get around to binding to the port yourself. So you should take the result of the test as more of a hint than an absolute rule, and (hopefully) have some way of handling it if you later find out that the port is in use after all.
Use a port number of 0. The OS will pick a free port.
http://msdn.microsoft.com/en-us/library/windows/desktop/ms740621(v=vs.85).aspx explains how the different options interact.
You haven't given us nearly enough information to tell us exactly what's going on in your use case, but I can work through one arbitrary use case that would look like what you're seeing.
Let's say you're on Win 2003 or later, and your primary NIC is 10.0.0.1, and everything is running under the same user account.
The first instance of your app comes up, and your test code tries to bind 10.0.0.1:12345 with SO_EXCLUSIVEADDREUSE. Of course this works.
You close the socket, then tell the HTTP server to listen to port 12345. It binds 0.0.0.0:12345 with SO_REUSEADDR, which of course works.
Now a second instance of your app comes up, and your test code tries to bind 10.0.0.1:12345 with SO_EXCLUSIVEADDREUSE. According to the chart in the MSDN article, that works.
You close the socket, then tell the HTTP server to listen to port 12345. It binds 0.0.0.0:12345 with SO_REUSEADDR, which works.
If this is the problem, assuming you can't get the HTTP server to bind a specific address, you can solve things by using 0.0.0.0 in your test code. (Of course if it's one of the other hundreds of possible problems, that solution won't work.)
If you don't know what socket options, address, etc. the HTTP server is using, and don't have the source, just run it in the debugger and breakpoint the relevant calls.
it is a little bit strange to me that boost.asio doesn`t use basic concept when client app connecting to the server - using IP address and port. May be I am a little bit noobie in Boost - and I accept that - but anyway I do not understand.
So, I have code like this to get client connected to the server on the localhost:
boost::asio::io_service io_service;
tcp::resolver resolver(io_service);
tcp::resolver::query query("localhost", "daytime");
tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
tcp::resolver::iterator end;
tcp::socket socket(io_service);
boost::system::error_code error = boost::asio::error::host_not_found;
while(error && endpoint_iterator != end) {
socket.close();
socket.connect(*endpoint_iterator++, error);
}
Windows in its WinSock 2.0 uses two parameters - IP and port - to identify the server. So, the qurestion is - how exactly Asio finds out which port is server listening to connections on? Does it scans all ports? And, if it does, what will happen if two servers listening on different ports at the same time?
Try,
tcp::resolver::query query("localhost", boost::lexical_cast<string>(port));//assuming port is an int
To answer your question, recall that you are starting the server on port 13. This happens to be the port which runs the Linux daytime service (http://www.sorgonet.com/linux/linuxdaemons/). Hence, they are subsequently able to use query("localhost","daytime") rather than specifying the port.
You are telling it that you want to connect to localhost on the port used by the daytime service. It will look up the appropriate port number in the services file (usually C:\WINDOWS\system32\drivers\etc\services under Windows, I believe /etc/services under Unix). You could also use an explicit port number there.
open netcat listen on port 13 on the localhost
it will accept the demo's connection. type some blabla when it connects and you'll see the output on the demo program
to run the netcat, run:
nc -l -p 13
windows? no netcat? install cygwin, and add netcat