I am facing a strange issue while trying to resolve endpoints using boost resolver in c++.
Case:
I am trying to connect to a website http://localhostIpAddress/test/ using boost.
where local address of server is "172.34.22.11"(say).
I am facing the error saying "resolve: No such host is known"
But when I am connecting to say website like google.com its able to resolve and connect successfully.
Also,even when I try to open "http:://localhostIpAddress/test/" in a browser, it opens successfully.
below is my code:
int main()
{
std::cout << "\nWebClient is starting... \n";
boost::asio::io_service IO_Servicehttp;
boost::asio::ip::tcp::resolver Resolverhttp(IO_Servicehttp);
std::string porthttp = "http";
boost::asio::ip::tcp::resolver::query Queryhttp("172.34.22.11/test/", porthttp);
boost::asio::ip::tcp::resolver::iterator EndPointIteratorhttp = Resolverhttp.resolve(Queryhttp);
g_ClientHttp = new HTTPClient(IO_Servicehttp, EndPointIteratorhttp);
}
catch (std::exception& e)
{
std::cerr << e.what();
}
}
In HTTPClient.cpp
HTTPClient::HTTPClient(boost::asio::io_service& IO_Servicehttp, boost::asio::ip::tcp::resolver::iterator EndPointIterhttp)
: m_IOServicehttp(IO_Servicehttp), m_Sockethttp(IO_Servicehttp),m_EndPointhttp(*EndPointIterhttp)
{
std::cout << "\n Entered: HTTPClient ctor \n";
boost::asio::ip::tcp::resolver::iterator endhttp;
boost::system::error_code error= boost::asio::error::host_not_found;
try
{
while (error && EndPointIterhttp != endhttp) //if error go to next endpoint
{
m_Sockethttp.async_connect(m_EndPointhttp,boost::bind(&HTTPClient::OnConnect_http, this, boost::asio::placeholders::error, ++EndPointIterhttp));
}
if(error)
throw boost::system::system_error(error);
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
}
m_IOServicehttp.run();
}
I have gone through a lot of website directed by google but haven't found anything related to this issue.
Any help or tip will be much appreciated
The hostname being resolved is invalid. Try changing the resolver's query host to "172.34.22.11". In the URL, "http://172.34.22.11/test/":
"http" is the protocol
"172.34.22.11" is the host which needs resolved
"/test/" is the path
At a high level, network communication occurs between the client and the server (host) over TCP. The client will create an HTTP request, include the path as part of the request, and write the complete request to a TCP socket. The server will read the HTTP request from a TCP socket, process the request based on the path, then write an HTTP response to the client over TCP.
Hostnames are concatenated with dots and specified to only allow:
ASCII letters 'a' through 'z'
digits
hyphen
Hence, "172.34.22.11/test/" contains invalid characters, and will likely not resolve. See RFC952 and RFC1123 for more details.
Related
I have one machine running simultaniously some C++ application and a Node.js server.
Use-case:
I want to be able to trigger my C++ application and make it pass some data (lets say a string) into a socket file. Then my Node.js server shall fetch that data from the socket and print it on some web page via a TCP-port (Code not included here/yet). The same should happen the other way around.
What I've done so far:
I was able to write some strings from my Node.js server into to the socket file with the following code:
server.js
var net = require('net');
var fs = require('fs');
var socketPath = '/tmp/sock';
fs.stat(socketPath, function(err) {
if (!err) fs.unlinkSync(socketPath);
var unixServer = net.createServer(function(localSerialConnection) {
localSerialConnection.on('data', function(data) {
// data is a buffer from the socket
console.log('Something happened!');
});
// write to socket with localSerialConnection.write()
localSerialConnection.write('HELLO\n');
localSerialConnection.write('I\'m\n');
localSerialConnection.write('DOING something!\n');
localSerialConnection.write('with the SOCKS\n');
});
unixServer.listen(socketPath);
});
reading the content with nc -U /tmp/sock and with the following output https://i.stack.imgur.com/ye2Dx.png.
When I run my C++ code:
cpp_socket.cpp
#include <boost/asio.hpp>
#include <iostream>
int main() {
using boost::asio::local::stream_protocol;
boost::system::error_code ec;
::unlink("/tmp/sock"); // Remove previous binding.
boost::asio::io_service service;
stream_protocol::endpoint ep("/tmp/sock");
stream_protocol::socket s(service);
std::cout << "passed setup section" << std::endl;
s.connect(ep);
std::cout << "passed connection" << std::endl;
std::string message = "Hello from C++!";
std::cout << "before sending" << std::endl;
boost::asio::write(s, boost::asio::buffer(message), boost::asio::transfer_all());
/* s.write_some(boost::asio::buffer("hello world!"), ec); */
std::cout << "after sending" << std::endl;
I get the following output:
/cpp_socket
passed setup section
terminate called after throwing an instance of 'boost::wrapexcept<boost::system::system_error>'
what(): connect: No such file or directory
Aborted (core dumped)
Even though the /tmp/sock file still exists.
When I remove ::unlink("/tmp/sock"); // Remove previous binding. with comments it runs through, but my Node.js server stops running and nc -U /tmp/sock looses its connection.
Neither the .write() nor the .write_some() function seems to work.
I assume that I miss something trivial or I'm not following basic concepts of unix socket communication.
Questions:
Is it even possible to listen with one Node.js server application to a TCP-port and a UNIX-socket at the same time?
Am I understanding the concept of unix socket communication correctly, judging from my input?
How can I read or write from C++ from/into a socket, preferably with C++ boost/asio library. But not necessarily necessary :-)
Am I asking the right questions?
As you might see, I'm not too experienced with these subjects. If I haven't addressed my issues accordingly and not precisely enough,it's due to my lack of experience.
Thanks a lot in advance. Lets have a fruitful discussion.
Oh oops. The error was in plain sight:
::unlink("/tmp/sock"); // Remove previous binding.
Removes the socket. That's not good if you wanted to connect to it.
Removing that line made it work:
passed setup section
passed connection: Success
before sending
after sending
And on the listener side:
Which is, I guess, to be expected because the client isn't complete yet.
Disclaimer:
I made it work with TCP sockets, but I would like to see how its possible with unix sockets. One more open port could lead to potential security threats (correct me if I'm wrong). So if you (sehe) or someone knows how to achieve this, please feel free to share. Since I wasn't able to find this in my searches over the internet, it could be helpful for others, too.
What I did now:
Creating a NodeJS server which is listening to two ports. One port for the web-browser and one for the C++ application
Connect the C++ application with one port
Sending strings using telnet
server.js
const net = require('net');
const express = require('express');
const app = express();
const c_port = 6666;
const si_port = 8888;
//------------- From here Browser stream is handled -------------//
app.get('/', (req, res)=>{
res.send('Hello from Node!');
});
app.get('/index.html', (req, res) => {
res.sendFile(__dirname + "/" + "index.html");
});
app.listen(si_port,(req, res)=>{
console.log(`Listening on http://localhost:${si_port}`);
});
//------------- From here C++ stream is handled -------------//
var server = net.createServer(function(c) { //'connection' listener
console.log('client connected');
c.on('end', function() {
console.log('client disconnected');
});
c.write('hello\r\n');
c.on('data', function(data){
var read = data.toString();
console.log(read);
// var message = c.read();
// console.log(message);
})
// c.pipe(c);
c.write('Hello back to C++'); // But only if you shut down the server
});
server.listen(c_port, function() { //'listening' listener
console.log(`Listening for input from C++ application on port:${c_port}`);
});
client.cpp
#include <iostream>
#include <boost/asio.hpp>
int main(int argc, char* argv[])
{
if(argc != 4){
std::cout<<"Wrong parameter\n"<<"Example usage ./client 127.0.0.1 1234 hello"<<std::endl;
return -1;
}
auto const address = boost::asio::ip::make_address(argv[1]);
auto const port = std::atoi(argv[2]);
std::string msg = argv[3];
msg = msg + '\n';
boost::asio::io_service io_service;
//socket creation
boost::asio::ip::tcp::socket socket(io_service);
//connection
boost::system::error_code ec;
socket.connect( boost::asio::ip::tcp::endpoint( address, port ),ec);
if(ec){std::cout<<ec.message()<<std::endl; return 1;}
// request/message from client
//const string msg = "Hello from Client!\n";
boost::system::error_code error;
boost::asio::write( socket, boost::asio::buffer(msg), error );
if(error){
std::cout << "send failed: " << error.message() << std::endl;
}
// getting response from server
boost::asio::streambuf receive_buffer;
boost::asio::read(socket, receive_buffer, boost::asio::transfer_all(), error);
if( error && error != boost::asio::error::eof ){
std::cout << "receive failed: " << error.message() << std::endl;
}
else{
const char* data = boost::asio::buffer_cast<const char*>(receive_buffer.data());
std::cout << data << std::endl;
}
return 0;
}
With telnet localhost 6666 I can easily on that port and send random strings.
Executing my binary with additional arguments and a string I was able to send some data from my C++: ./clientcpp 127.0.0.1 6666 "HELLO from C++". And here is the output:
Thanks a lot again.
I have a problem with websocket connection to wss://www.bitmex.com/realtime.
I found an axample in this question: Connect Websocket with Poco libraries , but I can't do the same with my wss:// address.
HTTPClientSession cs("wss://www.bitmex.com", 443);
HTTPRequest request(HTTPRequest::HTTP_CONNECT, "/realtime", HTTPMessage::HTTP_1_1);
request.set("origin", "wss://www.bitmex.com");
HTTPResponse response;
try {
WebSocket* m_psock = new WebSocket(cs, request, response);
//some code
}
catch (std::exception &e) {
std::cout << "Exception " << e.what();
}
I'm always receiving the exception: "Host not found" after string
WebSocket* m_psock = new WebSocket(cs, request, response);
HTTPClientSession takes a host string as the first param but you have given a host string with a protocol on the front.
The samples have a WebSocketServer in Net but sometimes you need to look at the test suite to find more details and it does require a little more work.
See WebSocketTest.cpp for a basic test that uses a WebSocket.
I am developing a HTTPS server that receives a request and must answer with 3 responses. The first two are something line ACKs, and the last one contains the requested information.
I am using my web browser (chrome) as client. What I want is the following:
The browser (client) sends a request to the server.
The server sends the first ACK (an html page) and the browser displays it.
After two seconds, the server send another ACK (a different html page) and the browser displays it.
After another two seconds, the server sends the requested information (a different html page) and the browser displays it.
The problem is that the browser only receives the first ACK, it seems that it is closing the socket after reading it, even setting the Connection to keep-alive in the HTTPS header.
Is there any way to be waiting for several HTTPS responses with the web browser?
Source
This contains the async methods executed by the server when a petition is made:
void handle_handshake(const boost::system::error_code& error)
{
if (!error)
{
boost::asio::async_read_until(socket_, request_, "\r\n\r\n",
boost::bind(&session::handle_read, this,
boost::asio::placeholders::error));
}
else
{
std::cout << "ERROR, deleting. " << __FILE__ << ":" << __LINE__ << std::endl;
delete this;
}
}
void handle_read(const boost::system::error_code& err)
{
if (!err)
{
std::string s = "some_response";
// First write. This write is received by the browser without problems.
boost::asio::async_write(socket_,
boost::asio::buffer(response),
boost::bind(&session::handle_write, this,
boost::asio::placeholders::error));
}
else
{
std::cout << "Error: " << err << "\n";
}
}
void handle_write(const boost::system::error_code& error)
{
if (!error)
{
if(n++ <= 2)
{
// Second and third writes.
// These ones are not read by the browser.
if(n == 1)
{
std::string s = "some_response2";
boost::asio::async_write(socket_,
boost::asio::buffer(response),
boost::bind(&session::handle_write, this,
boost::asio::placeholders::error));
}
else if (n==2)
{
std::string s = "some_response3";
boost::asio::async_write(socket_,
boost::asio::buffer(response),
boost::bind(&session::handle_write, this,
boost::asio::placeholders::error));
}
sleep(1);
}
}
else
{
std::cout << "ERROR, deleting: " << __FILE__ << ":" << __LINE__ << std::endl;
delete this;
}
}
Okay you want to overcome the slow start i.e taking a new connection and doing 3-way handshake for new connections— a full roundtrip of latency.
Although I could not get a proper code snippet of how you're doing this. A wild guess is you must have forgotten to set the timeout (SO_RCVTIMEO and SO_SNDTIMEO) for keep-alive connection or using a wrong HTTP version.
Note: Keep-alive connections are enabled by default in HTTP/1.1 while not in HTTP/1.0. HTTP/1.0 was designed to close the connection after every request between client and server. We can actually check this difference using telnet.
From the performance perspective, I wrote two (python) scripts — one uses the same connection for 50 consecutive requests and one initiates a new connection for every request.
Average time with keep-alive/persistent connections: 7.00 seconds
Average time with new connections: 22.38 seconds
It is a difference of almost 3 orders which makes sense as we know with keep-alive/persistent connections, the three-way handshake (a full roundtrip of latency) is avoided. The slow-start wouldn’t have much impact here because the request and response are quite small so the amount of bandwidth required is pretty low.
PS: Go through this in case it helps
boost::asio::ip::tcp::socket socket(io_service);
...
boost::asio::socket_base::keep_alive option;
socket.get_option(option);
Client need to keep the port open as servers are configured(pre-assumed) to listen to a particular application at a particular port
I got the above snippet from here
how to open socket for connecting to VK API, this code works good with other resources, but gives APPCRASH with api.vk.com. In browser it works with http, hence it should work here, and problem is not in 'http`, or am I wrong? Help!
P.S. I'm new to Boost and VK API, so if you can, explain it in details, thank you.
int main()
{
boost::asio::io_service io_service;
// Get a list of endpoints corresponding to the server name.
tcp::resolver resolver(io_service);
tcp::resolver::query query("api.vk.com", "http");
tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
// Try each endpoint until we successfully establish a connection.
tcp::socket socket(io_service);
boost::system::error_code error = boost::asio::error::host_not_found;
socket.connect(*endpoint_iterator, error);
return 0;
}
It looks like APPCRASH might be a thing you see in the Windows event log.
From that, I formed the hypothesis that you might be running this code in a windows service context.
Windows services do not have network access by default.
This means the DNS lookup may fail. You get an exception, e.g. resolve: Host not found (authoritative). This is what happens in a Linux console when I purposefully change the domain name to a nonexisting TLD:
$ ./test
terminate called after throwing an instance of 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::system::system_error> >'
what(): resolve: Host not found (authoritative)
Aborted (core dumped)
Because you don't handle the exception or check for errors, the program is abnormally terminated.
Fixed Demo
Note:
I opted to handle errors rather than exceptions.
You failed to loop through the query results (using only the first without even checking whether it was valid)
Coliru, much like a restricted windows service, does not allow network connectivity outside the loopback adaptor either, so it shows a proper error
Live On Coliru
#include <boost/asio.hpp>
#include <iostream>
using boost::asio::ip::tcp;
int main()
{
boost::asio::io_service io_service;
boost::system::error_code error = boost::asio::error::host_not_found;
// Get a list of endpoints corresponding to the server name.
tcp::resolver resolver(io_service);
tcp::resolver::query query("api.vk.com", "http");
tcp::resolver::iterator endpoint_iterator = resolver.resolve(query, error), last;
if (!error) {
// Try each endpoint until we successfully establish a connection.
tcp::socket socket(io_service);
for (;endpoint_iterator != last; ++endpoint_iterator) {
socket.connect(*endpoint_iterator, error);
if (!error) {
std::cout << "Successfully connected to " << endpoint_iterator->endpoint() << "\n";
break; // found working endpoint
} else {
std::cout << "Skipped " << endpoint_iterator->endpoint() << " - not connecting\n";
}
}
return 0;
} else {
std::cout << error.message() << "\n";
return 255;
}
}
On my system it prints
Successfully connected to 87.240.131.97:80
I simply changed my DNS server and it works: Successfully connected to 87.240.131.119:80
Im following the tutorials at the boost official web site http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/tutorial/tutdaytime1.html.
The program is working perfectly if i connect to "localhost" or "127.0.0.1" on the same machine. But if i run the client on another computer with the same network it fails to connect to the server. Why is this happening? and what would i have to do to get the client to run on another network?
Error: connect: No connection could be made because the target machine actively refused it.
Client:
#include <iostream>
#include <boost/array.hpp>
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
int main()
{
try
{
boost::asio::io_service io_service;
tcp::resolver resolver(io_service);
char* serverName = "localhost";
tcp::resolver::query query(serverName, "daytime");
tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
tcp::socket socket(io_service);
while(true)
{
boost::asio::connect(socket, endpoint_iterator);
for (;;)
{
boost::array<char, 128> buf;
boost::system::error_code error;
size_t len = socket.read_some(boost::asio::buffer(buf), error);
if (error == boost::asio::error::eof)
break; // Connection closed cleanly by peer.
else if (error)
throw boost::system::system_error(error); // Some other error.
std::cout.write(buf.data(), len);
std::cout <<"\n";
}
}
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
}
return 0;
}
Server:
#include <iostream>
#include <string>
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
int main()
{
try
{
boost::asio::io_service io_service;
tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), 13));
for (;;)
{
tcp::socket socket(io_service);
acceptor.accept(socket);
std::string message = "This is the Server!";
boost::system::error_code ignored_error;
boost::asio::write(socket, boost::asio::buffer(message), ignored_error);
}
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
}
return 0;
}
I would guess your problem might be that you return on the first error. Resolving gives you an iterator on a number of endpoints. You try the first of those and if it does not work out you give up instead of letting the iterator go on.
Again, i am by no means an expert in boost::asio and far less in its TCP world but resolve may return more than one endpoint (for example IPv4 and IPv6) and possibly only one of them does not work out here.
For testing you could create the endpoint yourself by first creating a ip::address object, using its from_string() method to give it the address of the server (works only on your local network of course) and then using it for your endpoint:
boost::asio::ip::address address;
address.from_string("the.servers.ip.here");
boost::asio::ip::tcp::endpoint endpoint(address, 13);
boost::asio::connect(socket, endpoint);
And see if that works. If not, it probably is a problem on the server side.
To run the server and client on separate networks, Make the client connect to the servers external ip address. This is obvious but external ip addresses constantly change so to solve this problem you can go to www.noip.com and create a name that links to your ip address. This way in the client all you have to do is specify a name instead of an ip address.
most likely firewall issue, if you are using windows for server check windows firewall, if you are using linux, check the iptables.