I'm trying to create an HTTP client using Boost Asio. I copied the sync client example from asio, compile, then run. Unfortunately, on my logs, it shows Service not found. When I traced the code, I found it that it is thrown from the following code:
boost::asio::io_service io_service;
// Get a list of endpoints corresponding to the server name.
tcp::resolver resolver(io_service);
//->if i removed the http, it has no error
tcp::resolver::query query("host.com", "http");
//->This part throws the service not found
tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
tcp::resolver::iterator end;
Can anybody explain why it is throwing service not found or on how can I solve this?
This means the OS does not know which port number corresponds to the TCP service with the name "http".
On a unix-like OS, this would mean the line http 80/tcp is missing from /etc/services, I am able to reproduce the error on Linux by commenting that line out.
If the OS cannot be configured to use services, you may use any service "" in the resolver, and specify the port number explicitly when creating the endpoint object for the connect call:
tcp::endpoint connectionEndpoint(endpoint_iterator->address(), 80);
boost::system::error_code ec;
socket.connect(connectionEndpoint, ec);
Related
I am a little confused about which type of resolver I should use for a side project I am working on. I am not finding the answer in the asio documentation.
I know that DNS can work with both UDP or TCP and that larger responses are generally sent over TCP.
asio offers both ip::tcp::resolver and ip::udp::resolver.
Can I use them interchangeably?
After I have resolved the name to an endpoint, I plan to connect with
a TCP socket. Does that mean I have to use a ip::tcp::resolver?
If there are in fact interchangeable:
Is there a performance benefit to using the UDP resolver?
Is there a some other benefit to using the TCP resolver?
If I use UDP resolver, do I need to deal with the response being too large for the UDP lookup and retry with TCP? (I expect to connect to a CDN that will resolve to multiple IP addresses per host)
Use the resolver that has the same protocol as the socket. For example, tcp::socket::connect() expects a tcp::endpoint, and the endpoint type provided via udp::resolver::iterator is udp::endpoint. Attempting to directly use the result of the query from a different protocol will result in a compilation error:
boost::asio::io_service io_service;
boost::asio::ip::tcp::socket socket(io_service);
boost::asio::ip::udp::resolver::iterator iterator = ...;
socket.connect(iterator->endpoint());
// ~~~^~~~~~~ no matching function call to `tcp::socket::connect(udp::endpoint)`
// no known conversion from `udp::endpoint` to `tcp::endpoint`
Neither tcp::resolver nor udp::resolver dictate the transport layer protocol the name resolution will use. The DNS client will use TCP when either it become necessary or it has been explicitly configured to use TCP.
On systems where service name resolution is supported, when performing service-name resolution with a descriptive service name, the type of resolver can affect the results. For example, in the IANA Service Name and Transport Protocol Port Number Registry:
the daytime service uses port 13 on UDP and TCP
the shell service uses port 514 only on TCP
the syslog service uses port 514 only on UDP
Hence, one can use tcp::resolver to resolver the daytime and shell service, but not syslog. On the other hand, udp::resolver can resolve daytime and syslog, but not shell. The following example demonstrates this distinction:
#include <boost/asio.hpp>
int main()
{
boost::asio::io_service io_service;
using tcp = boost::asio::ip::tcp;
using udp = boost::asio::ip::udp;
boost::system::error_code error;
tcp::resolver tcp_resolver(io_service);
udp::resolver udp_resolver(io_service);
// daytime is 13/tcp and 13/udp
tcp_resolver.resolve(tcp::resolver::query("daytime"), error);
assert(!error);
udp_resolver.resolve(udp::resolver::query("daytime"), error);
assert(!error);
// shell is 514/tcp
tcp_resolver.resolve(tcp::resolver::query("shell"), error);
assert(!error);
udp_resolver.resolve(udp::resolver::query("shell"), error);
assert(error);
// syslog is 514/udp
tcp_resolver.resolve(tcp::resolver::query("syslog"), error);
assert(error);
udp_resolver.resolve(udp::resolver::query("syslog"), error);
assert(!error);
tcp_resolver.resolve(tcp::resolver::query("514"), error);
assert(!error);
udp_resolver.resolve(udp::resolver::query("514"), error);
assert(!error);
}
I am trying to figure out how to limit a tcp socket to localhost. I finally found code that will compile, but it does not accept any connections.
The code accepts connections with endpoint_all, but not with "endpoint_local" variable set with tcp::endpoint(ip::address::from_string("127.0.0.1"),port2);
boost::asio::io_service io_service;
short port = 9000;
tcp::endpoint endpoint_all = boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(),port);
tcp::endpoint endpoint_local = boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string("127.0.0.1"),port);
try
{
server s(io_service, std::atoi("9000"),endpoint_all);
io_service.run();
}
catch (std::exception& e)
{
}
Update: I can access the socket via "telnet 127.0.0.1 9000" and "telnet localhost 9000". The actual application in question (PHP XDebug) does not connect to the ip limited endpoint, but does otherwise.
"telnet localhost 9000" give the following error, but does connect. I don't connect have localhost in php.ini, but maybe this message is related. "Connection refused for ::1:"
I think it would be proper to allow connections to ::1: regardless of if this is the bug or not.
Trying ::1...
telnet: connect to address ::1: Connection refused
Trying fe80::1...
telnet: connect to address fe80::1: Connection refused
Trying 127.0.0.1...
Connected to localhost.
Judging from the error message "Connection refused for ::1" it seems that PHP XDebug tries to connect to ::1 which is the IPv6 equivalent of 127.0.0.1.
Hand this address to boost asio in order to listen to IPv6 connections:
tcp::endpoint endpoint_local = tcp::endpoint(boost::asio::ip::address::from_string("::1"),port);
Do it like that
boost::asio::ip::tcp::resolver resolver(io_service);
resolver.async_resolve({"localhost", std::to_string(port).data()}, [self{shared_from_this()}](auto ec, auto res) {
if(ec || res.empty()) {
return;
}
auto endpoint = boost::asio::ip::tcp::endpoint(*res.begin());
});
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 need to create a C++ FastCGI server and connect to it in the simplest way possible in order to test/develop incrementally.
I have both an issue conceptually and with the lack of API documentation for FastCGI. My understanding is that when I do
FCGX_Request request;
FCGX_Init();
FCGX_InitRequest(&request, 0, 0);
while (FCGX_Accept_r(&request) == 0) {
}
This opens a socket and listens on it for requests. Then, using boost::asio, I want to do something like
boost::asio::io_service io_service;
boost::system::error_code error;
using boost::asio::ip::tcp;
tcp::resolver resolver(io_service);
tcp::resolver::query query("localhost", "" /* WTF are the params here? */);
tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
tcp::socket socket(io_service);
boost::asio::connect(socket, endpoint_iterator);
while (true)
{
boost::array<char, 128> buf;
size_t len = socket.read_some(boost::asio::buffer(buf), error);
if (error)
break;
}
CPPUNIT_ASSERT_EQUAL(error, (boost::system::error_code)boost::asio::error::eof);
I.e. to programmatically send a request to the FastCGI process to test it's working.
Anyway, I believe that tcp::resolver::query is the key to setting up communication from my simple unit test.
However,
I don't fully understand what a 'socket' is in this case. I've read that it's just a file (on linux)?
Given this, how do I know what socket FastCGI is listening on?
How do I specify the socket to boost::asio?
How do I stop the FastCGI process from listening once the test is done?
I'm possibly going about this all wrong, so any hints on the proper way to approach this simple test case would be gratefully accepted. Also, if anyone knows where the hell the API documentation for fcgi/fcgi++/fastcgi++ is, that would be awesome.
Your question is really only about elementary networking.
Edit Check out this most valued internet resource on network programming (basics to advanced):
What is a socket? from Beej's network programming guide
A socket is a connection. A server is listening on a /port/ (TCP or UDP. Assuming
TCP for the rest, since you're doing CGI).
Clients connect to the port and the server accepts the connection, resulting in a socket (bidirectional stream, so to speak). The client now (usually) sends and the server receives the request. Then the server sends the response. (The connection may be closed, or kept alive depending on the protocol/preferences).
Specific answers:
query("localhost", "http");
would end up connecting to port 80 on most systems.
Of course you can also just specify the port number there:
query("localhost", "8080");
Choose the port number that the server bound it's listener to.
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