Make a ping function with QTcpSocket - c++

I want to make a ping function with Qt (and don't like the QProcess execution system ping way).
Here's the demo code,
void SimmplePing(const QString& sAddress, int port=80)
{
QTcpSocket messenger;
messenger.connectToHost(sAddress, port);
if (!messenger.waitForConnected(3000))
{
qDebug() << messenger.error();
}
else
{
qDebug() << "OK";
}
}
void test()
{
SimmplePing("182.34.19.222", 80);
}
I test it with "192.168.0.1" (my router IP) and "www.baidu.com" both can work.
But I test it "182.34.19.222" failed with QAbstractSocket::SocketTimeoutError error message.
However, pinging it within system cmd can work properly. Couldn't figure out why.

The main difference here is that the ping command as it's normally used, uses the ICMP protocol which doesn't use TCP for communication. Trying to connect to a host via websockets using TCP is handled in a different way. If the TCP socket of the host you're trying to connect to doesn't listen on the specified port, in this case port 80, you won't recieve an answer, which can lead to the behaviour you encountered.
(https://en.wikipedia.org/wiki/Internet_Control_Message_Protocol)

Related

Why is the C++ httplib library blocking my main thread after creating the server?

I'm trying to understand the behavior of the C++ httplib library. It appears to be blocking my main thread, but I don't believe it always did this. My relevant code looks like this:
Server server;
String address = "192.168.1.200";
int port = 4000;
server.Get("/getAsset", [this](const Request& req, httplib::Response& res)
{
res.set_header("Access-Control-Allow-Origin", "*");
auto info = getAssetData();
res.set_content(GetResponse(info), "application/json");
});
server.listen(address.c_str(), port, 0);
I'm running the code above on my laptop, and my laptop's IP is 192.168.1.200, so the server is running on my computer. What's interesting is if I pass in an IP from some other network interface on my computer (i.e. 169.254.143.40), the server doesn't block the main thread anymore.
From looking at the source code in httplib, I did make an observation. Consider the source code in httplib, below:
inline bool Server::listen(const char *host, int port, int socket_flags) {
if (bind_internal(host, port, socket_flags) < 0) return false;
return listen_internal();
}
When I pass in my IP (192.168 ...), the code returns listen_internal().
When I pass in another IP from a different network interface on my laptop (169.254 ...), the code returns false.
Any ideas on why all of this is happening?
The Server::listen is intended to be blocking. As you see in the code, it tries to bind the port on the interface and if it succeeds, it listens indefinitely to accept clients.
If it cannot bind the interface (by example because it doesn't exists), the function will return false to indicate an error. The listen loop can also return an error if the socket becomes closed.
As usual the examples don't give the code for error handling. A more accurate sample would be:
if(!server.listen(address.c_str(), port, 0))
{
std::cerr<<"Server stopped in error state\n";
return EXIT_FAILURE;
}
If you want to listen on all addresses, use "0.0.0.0" as the binding interface.

Unable to connect to establish a socket connection using QTcpSocket to a linux box (telnet works)

code:
watchTowerSocket = new QTcpSocket();
watchTowerSocket->connectToHost("198.168.101.230", 4400);
if(watchTowerSocket->waitForConnected())
{
qDebug() << "Connected";
watchTowerSocket->write("HELLO SERVER");
}
else
{
qDebug() << "Not Connected";
}
When I run my application, I get "Connected" on the console. However, my server (which is running on a linux box) does not receive a connection. Also, I ran wireshark and found that no TCP packet is getting generated when the above code is being run.
What must I try to fix this?

CSocket does not work on LAN

I'm learning network-programming and try to develop a simple socket application that used CSocket class from MFC. And found myself hitting a wall that need some help.
I want the server side listens on a certain port, example 1001. Then from other computer, on the same sub-net, it should successfully telnet to that port. My program works correctly on localhost, but fail on the LAN, although I have opened that port on firewall of listener.
Here is my code from listener:
//CListenSocket is derived from CSocket
CListenSocket myListener;
myListener.Create(1001);
myListener.Listen();
//OnAccept()
//CConnectSocket is also derived from CSocket
CConnectSocket myConnect;
myListener.Accept(myConnect);
I built the release version using VS2008, here is the screenshot of the configuration properties:
So at this stage, when I run the program, netstat -an show this line:
TCP 0.0.0.0:1001 0.0.0.0:0 LISTENING
Then on that machine telnet 127.0.0.1 1001, this line appears.
TCP 127.0.0.1:1001 127.0.0.1:2681 ESTABLISHED
So I think my code is correct. After that I tried from other machine with the same sub-net, and the telnet fail:
Connecting To 192.168.2.199...Could not open connection to the host, on port 1001: Connect failed
Note: that my listener is on 192.168.2.199, and the connector is on 192.168.2.3. Both nodes can successfully ping and sharing file with each other. I also add both Inbound Rule and Outbound Rule for the program on my firewall, here is the properties of the rule:
For more information: On my listener node, there is Apache HTTP server installed on it, so I have the other node telnet to port 80, and it works...
So where did I miss? please help, thank you in advance.
EDITION 1:
Attempt for troubleshooting
So after hitting my head to the table for a while, I quickly make a decision for not use telnet for client anymore. But make a small client program to catch errors:
//CClientSocket is derived from CSocket
CClientSocket clientSocket;
clientSocket.Create();
int iConnect = clientSocket.Connect(ipAddress,1001) //ipAddress is a variable of MFC's text box on GUI.
switch (iConnect)
{
case 0:
{
DWORD errorNumber = ::GetLastError(); //catch error code
CString s_errorNumber;
s_errorNumber.Format("%d",errorNumber); //format to CString for easy echo
MessageBox("Connection fail :"+s_errorNumber)
clientSocket.ShutDown(CAsyncSocket::both);
clientSocket.Close();
break;
case SOCKET_ERROR:
if (::GetLastError() != WSAEWOULDBLOCK)
clientSocket.ShutDown(CAsyncSocket::both);
else
clientSocket.AsyncSelect();
break;
default:
{
MessageBox("Connection Established.");
}
break;
}
And the error number is: 10061. I checked this code on MSDN an it is WSAECONNREFUSED-Connection refused.
Now we know the problem here must be somewhere in the listener's firewall... still hiting my head to the table.

QTcpSocket and Specifying Client Outgoing Network Device

Windows 8.1 user here, using Qt 5.3. Trying to learn network programming (please bear with me). Let's say I have two network devices on my machine. One is assigned the IP 192.168.1.2, and the other 192.168.1.3. The first device has priority.
My goal is to create a QTcpServer on 192.168.1.2 and a QTcpSocket client on 192.168.1.3. The way I envision this would work is the data packets from the client will start at 192.168.1.3 (on some port), travel to the router, then to the server at 192.168.1.2 (on some port). Ok, hopefully this sounds reasonable.
Here's the problem. I can't find a functioning way to specify an outgoing address with QTcpSocket. There appears to be a bind method, but it doesn't do much. Each time I send that from the client, it travels on the default device at 192.168.1.2.
socket = new QTcpSocket(this);
qDebug() << socket->localAddress(); // shows "0"
qDebug() << socket->localPort(); // shows "0"
socket->bind(QHostAddress("192.168.1.3"), 50000);
qDebug() << socket->localAddress(); // shows "50000"
qDebug() << socket->localPort(); // shows "0"
//socket->setLocalAddress(QHostAddress("192.168.1.4")); // error, says it's protected
//socket->setLocalPort("50000"); // error, says it's protected
//qDebug() << socket->localAddress();
//qDebug() << socket->localPort();
socket->connectToHost("google.com", 80); // network manager shows data on 192.168.1.2
Any ideas?

boost asio server-client. Connect between two computers in local area network

I wrote a program to synchronize files between two computers in the same local area network, just like the DropBox. It works perfectly to synchronize files from one folder to another folder in the same computer, but when I want to test the program between two computers, it fails to connect to another computer.
my router's IP is 192.168.1.1, one host's IP is 192.168.1.101(host A), another's is 192.168.1.107(host B), they are all in the same local area network. host A runs the client program, host B runs the server program. when host A tries to connect to host B, it fails and displays the message as below:
A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond
I just don't know what's the problem in connecting to another computer in my local area network, and I display the connection code.
client:
bool Send::CheckConnect(boost::asio::ip::tcp::socket& socket)
{
boost::asio::io_service io_connect;
boost::asio::ip::tcp::resolver resolver(io_connect);
boost::asio::ip::tcp::resolver::query query("192.168.1.107", "6873");
boost::asio::ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query), end;
boost::system::error_code error_connect;
unsigned short count = 0;
while( count < 3 )
{
++count;
if( boost::asio::connect(socket, endpoint_iterator, error_connect) != end )
return true;
}
std::cout<<boost::system::system_error(error_connect).what()<<std::endl;
return false;
}
server:
boost::asio::io_service io_sev;
boost::asio::ip::tcp::acceptor accept_server( io_sev, boost::asio::ip::tcp::endpoint
(boost::asio::ip::tcp::v4(), 6873) );
unsigned count = 0;
boost::asio::ip::tcp::socket socket_server(io_sev);
On Server side, I dont see any accept or async_accept !
you need something like:
void ConnectionServer::creatSocketAndAccept()
{
//Accept the next connection.
acceptor.async_accept(socket,
boost::bind(&ConnectionServer::handle_accept, this, boost::asio::placeholders::error)
);
}
in case of accept (since you used connect not async_connect) you dont need to provide the boost::bind for accept handler.
hope that helps