I am trying to a set a timeout for a socket that I have created using ASIO in boost with no luck. I have found the following code elsewhere on the site:
tcp::socket socket(io_service);
struct timeval tv;
tv.tv_sec = 5;
tv.tv_usec = 0;
setsockopt(socket.native(), SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
setsockopt(socket.native(), SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
boost::asio::connect(socket, endpoint_iterator);
The timeout remains at the same 60 seconds as opposed to the 5 seconds I am looking for in the connect call. What am I missing? Note the connect code works fine in all other cases (where there is no timeout).
The socket options you've set don't apply to connect AFAIK.
This can be accomplished by using the asynchronous asio API as in the following asio example.
The interesting parts are setting the timeout handler:
deadline_.async_wait(boost::bind(&client::check_deadline, this));
Starting the timer
void start_connect(tcp::resolver::iterator endpoint_iter)
{
if (endpoint_iter != tcp::resolver::iterator())
{
std::cout << "Trying " << endpoint_iter->endpoint() << "...\n";
// Set a deadline for the connect operation.
deadline_.expires_from_now(boost::posix_time::seconds(60));
// Start the asynchronous connect operation.
socket_.async_connect(endpoint_iter->endpoint(),
boost::bind(&client::handle_connect,
this, _1, endpoint_iter));
}
else
{
// There are no more endpoints to try. Shut down the client.
stop();
}
}
And closing the socket which should result in the connect completion handler to run.
void check_deadline()
{
if (stopped_)
return;
// Check whether the deadline has passed. We compare the deadline against
// the current time since a new asynchronous operation may have moved the
// deadline before this actor had a chance to run.
if (deadline_.expires_at() <= deadline_timer::traits_type::now())
{
// The deadline has passed. The socket is closed so that any outstanding
// asynchronous operations are cancelled.
socket_.close();
// There is no longer an active deadline. The expiry is set to positive
// infinity so that the actor takes no action until a new deadline is set.
deadline_.expires_at(boost::posix_time::pos_infin);
}
// Put the actor back to sleep.
deadline_.async_wait(boost::bind(&client::check_deadline, this));
}
Related
I'm working on a vision-application, which have two modes:
1) parameter setting
2) automatic
The problem is in 2), when my app waits for a signal via TCP/IP. The program is freezing while accept()-methode is called. I want to provide the possibility on a GUI to change the mode. So if the mode is changing, it's provided by another signal (message_queue). So I want to interrupt the accept state.
Is there a simple possibility to interrupt the accept?
std::cout << "TCPIP " << std::endl;
client = accept(slisten, (struct sockaddr*)&clientinfo, &clientinfolen);
if (client != SOCKET_ERROR)
cout << "client accepted: " << inet_ntoa(clientinfo.sin_addr) << ":"
<< ntohs(clientinfo.sin_port) << endl;
//receive the message from client
//recv returns the number of bytes received!!
//buf contains the data received
int rec = recv(client, buf, sizeof(buf), 0);
cout << "Message: " << rec << " bytes and the message " << buf << endl;
I read about select() but I have no clue how to use it. Could anybody give me a hint how to implement for example select() in my code?
Thanks.
Best regards,
T
The solution is to call accept() only when there is an incoming connection request. You do that by polling on the listen socket, where you can also add other file descriptors, use a timeout etc.
You did not mention your platform. On Linux, see epoll(), UNIX see poll()/select(), Windows I don't know.
A general way would be to use a local TCP connection by which the UI thread could interrupt the select call. The general architecture would use:
a dedicated thread waiting with select on both slisten and the local TCP connection
a TCP connection (Unix domain socket on a Unix or Unix-like system, or 127.0.0.1 on Windows) between the UI thread and the waiting one
various synchronizations/messages between both threads as required
Just declare that select should read slisten and the local socket. It will return as soon as one is ready, and you will be able to know which one is ready.
As you haven't specified your platform, and networking, especially async, is platform-specific, I suppose you need a cross-platform solution. Boost.Asio fits perfectly here: http://www.boost.org/doc/libs/1_39_0/doc/html/boost_asio/reference/basic_socket_acceptor/async_accept/overload1.html
Example from the link:
void accept_handler(const boost::system::error_code& error)
{
if (!error)
{
// Accept succeeded.
}
}
...
boost::asio::ip::tcp::acceptor acceptor(io_service);
...
boost::asio::ip::tcp::socket socket(io_service);
acceptor.async_accept(socket, accept_handler);
If Boost is a problem, Asio can be a header-only lib and used w/o Boost: http://think-async.com/Asio/AsioAndBoostAsio.
One way would be to run select in a loop with a timeout.
Put slisten into nonblocking mode (this isn't strictly necessary but sometimes accept blocks even when select says otherwise) and then:
fd_set read_fds;
FD_ZERO(&read_fds);
FD_SET(slisten, &read_fds);
struct timeval timeout;
timeout.tv_sec = 1; // 1s timeout
timeout.tv_usec = 0;
int select_status;
while (true) {
select_status = select(slisten+1, &read_fds, NULL, NULL, &timeout);
if (select_status == -1) {
// ERROR: do something
} else if (select_status > 0) {
break; // we have data, we can accept now
}
// otherwise (i.e. select_status==0) timeout, continue
}
client = accept(slisten, ...);
This will allow you to catch signals once per second. More info here:
http://man7.org/linux/man-pages/man2/select.2.html
and Windows version (pretty much the same):
https://msdn.microsoft.com/pl-pl/library/windows/desktop/ms740141(v=vs.85).aspx
I have the following bit of ASIO code, that synchronously reads UDP packets. The problem is if no data packets of the given size have arrived in a given time frame (30 seconds) I'd like the recieve_from function to return with some kind of error to specif icy timeout.
for (;;)
{
boost::array<char, 1000> recv_buf;
udp::endpoint remote_endpoint;
asio::error_code error;
socket.receive_from(asio::buffer(recv_buf), // <-- require timeout
remote_endpoint, 0, error);
if (error && error != asio::error::message_size)
throw asio::system_error(error);
std::string message = make_daytime_string();
asio::error_code ignored_error;
socket.send_to(asio::buffer(message),
remote_endpoint, 0, ignored_error);
}
Looking at the documentation non of the UDP oriented calls support a time-out mechanism.
What is the correct way (also portable if possible) for having a time-out with syncronous UDP calls in ASIO?
As far as I know, this is not possible. By running a synchronous receive_from you've blocked code execution by a syscall recvmsg from #include <sys/socket.h>.
As portability goes, I cannot speak for Windows but a linux/bsd C-flavoured solution would look like this:
void SignalHandler(int signal) {
// do what you need to do, possibly informing about timeout and calling exit()
}
...
struct sigaction signal_action;
signal_action.sa_flags = 0;
sigemptyset(&signal_action.sa_mask);
signal_action.sa_handler = SignalHandler;
if (sigaction(SIGALRM, &signal_action, NULL) == -1) {
// handle error
}
...
int timeout_in_seconds = 5;
alarm(timeout_in_seconds);
...
socket.receive_from(asio::buffer(recv_buf), remote_endpoint, 0, error);
...
alarm(0);
If this is not at all feasible, I would recommend going full async and run it in a boost::asio::io_service.
I currently use Windows 7 64bit, MSVC2010 and Boost.Asio 1.57. I would like to connect to a TCP server with a timeout. If the timeout expires, I should close the connection as soon as possible as the IP address (chosen by a user) is probably wrong.
I know I should use async requests because sync requests have no timeouts options included. So I'm using async_connect with an external timeout. This is a solution I have found in many places, including stackoverflow.
The problem is that the following code does not behave like I wished. async_connect is not "cancelled" by the socket.close(). With my computer, closing the socket takes about 15 seconds to complete, which makes my program not responsive for a while...
I would like to have a decent timeout (approx. 3 seconds) and close the socket after this time, so that the user can try to connect with another IP address (from the HMI)
#include <iostream>
#include <boost\asio.hpp>
#include <boost\shared_ptr.hpp>
#include <boost\bind.hpp>
using boost::asio::ip::tcp;
class tcp_client
{
public:
tcp_client(boost::asio::io_service& io_service, tcp::endpoint& endpoint, long long timeout = 3000000)
:m_io_service (io_service),
m_endpoint(endpoint),
m_timer(io_service),
m_timeout(timeout)
{
connect();
}
void stop()
{
m_socket->close();
}
private:
void connect()
{
m_socket.reset(new tcp::socket(m_io_service));
std::cout << "TCP Connection in progress" << std::endl;
m_socket->async_connect(m_endpoint,
boost::bind(&tcp_client::handle_connect, this,
m_socket,
boost::asio::placeholders::error)
);
m_timer.expires_from_now(boost::posix_time::microseconds(m_timeout));
m_timer.async_wait(boost::bind(&tcp_client::HandleWait, this, boost::asio::placeholders::error));
}
void handle_connect(boost::shared_ptr<tcp::socket> socket, const boost::system::error_code& error)
{
if (!error)
{
std::cout << "TCP Connection : connected !" << std::endl;
m_timer.expires_at(boost::posix_time::pos_infin); // Stop the timer !
// Read normally
}
else
{
std::cout << "TCP Connection failed" << std::endl;
}
}
public:
void HandleWait(const boost::system::error_code& error)
{
if (!error)
{
std::cout << "Connection not established..." << std::endl;
std::cout << "Trying to close socket..." << std::endl;
stop();
return;
}
}
boost::asio::io_service& m_io_service;
boost::shared_ptr<tcp::socket> m_socket;
tcp::endpoint m_endpoint;
boost::asio::deadline_timer m_timer;
long long m_timeout;
};
int main()
{
boost::asio::io_service io_service;
tcp::endpoint endpoint(boost::asio::ip::address_v4::from_string("192.168.10.74"), 7171); // invalid address
tcp_client tcpc(io_service, endpoint);
io_service.run();
system("pause");
}
The only solution I found is to run io_service:run() in many threads, and create a new socket for each connection. But this solution does not appear valid to me as I have to specify a number of threads and I don't know how many wrong address the user will enter in my HMI. Yes, some users are not as clever as others...
What's wrong with my code ? How do I interrupt a TCP connection in a clean and fast way ?
Best regards,
Poukill
There's nothing elementary wrong with the code, and it does exactly what you desire on my Linux box:
TCP Connection in progress
Connection not established...
Trying to close socket...
TCP Connection failed
real 0m3.003s
user 0m0.002s
sys 0m0.000s
Notes:
You may have success adding a cancel() call to the stop() function:
void stop()
{
m_socket->cancel();
m_socket->close();
}
You should check for abortion of the timeout though:
void HandleWait(const boost::system::error_code& error)
{
if (error && error != boost::asio::error::operation_aborted)
{
std::cout << "Connection not established..." << std::endl;
std::cout << "Trying to close socket..." << std::endl;
stop();
return;
}
}
Otherwise the implicit cancel of the timer after successful connect will still close() the socket :)
If you want to run (many) connection attempts in parallel, you don't need any more threads or even more than one io_service. This is the essence of Boost Asio: you can do asynchronous IO operations on a single thread.
This answer gives a pretty isolated picture of this (even though the connections are done using ZMQ there): boost asio deadline_timer async_wait(N seconds) twice within N seconds cause operation canceled
another example, this time about timing out many sessions independently on a single io_service: boost::asio::deadline_timer::async_wait not firing callback
I have a QTcpSocket and I am reading into a loop. Each time a full packet has been read, or there has been an error, I manually check the status of the socket inside the loop, with:
while(true){
if(socket->state()==QAbstractSocket::ConnectedState){
qDebug()<<"Socket status: connected. Looking for packets...";
if(socket->waitForReadyRead(2000)){
//...
}
When I execute de program, once connected and the loop starts, it always prints qDebug()<<"Socket status: connected. Looking for packets..."; and then stucks at waitForReadyRead until some data is ready to be read.
The problem is that disconnections are not detected. If I disconnect from network from the OS options, or even if I unplug the ethernet wire, it behaves the same: Socket state equals QAbstractSocket::ConnectedState, so it goes on, but without receiving anything of course.
I also tried to detect disconnections connecting disconnected() signal (after fist connection) to a reconnect function:
// Detect disconnection in order to reconnect
connect(socket, SIGNAL(disconnected()), this, SLOT(reconnect()));
void MyClass::reconnect(){
qDebug()<<"Signal DISCONNECTED emitted. Now trying to reconnect";
panelGUI->mostrarValueOffline();
socket->close();
prepareSocket((Global::directionIPSerialServer).toLocal8Bit().data(), 8008, socket);
qDebug()<<"Reconnected? Status: "<<socket->state();
}
But signal is never emited, because this code is never executed. Which is logical, since it looks like socket state is always ConnectedState.
If I plug again, connection is restored and starts to receive data again, but I do want to detect disconnections to show "Disconnected" at the GUI.
Why is QTcpSocket behaving this way, and how can I solve this problem?
EDIT: I'm creating socket at the class constructor, and then initialising calling prepareSocket function:
socket = new QTcpSocket();
socket->moveToThread(this);
bool prepareSocket(QString address, int port, QTcpSocket *socket) {
socket->connectToHost(address, port);
if(!socket->waitForConnected(2000)){
qDebug()<<"Error creating socket: "<<socket->errorString();
sleep(1);
return false;
}
return true;
}
Finally found the solution in this Qt forum:
If no data is exchanged for a certain while, TCP will start sending
keep-alive segments (basically, ACK segments with the acknowledgement
number set to the current sequence number less one). The other peer
then replies with another acknowledgement. If this acknowledgment is
not received within a certain number of probe segments, the connection
is automatically dropped. The little problem is that the kernel starts
sending keep-alive segments after 2 hours since when the connection
becomes idle! Therefore, you need to change this value (if your OS
allows that) or implement your own keep-alive mechanism in your
protocol (like many protocols do, e.g. SSH). Linux allows you to
change it using setsockopt:
int enableKeepAlive = 1;
int fd = socket->socketDescriptor();
setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &enableKeepAlive, sizeof(enableKeepAlive));
int maxIdle = 10; /* seconds */
setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &maxIdle, sizeof(maxIdle));
int count = 3; // send up to 3 keepalive packets out, then disconnect if no response
setsockopt(fd, SOL_TCP, TCP_KEEPCNT, &count, sizeof(count));
int interval = 2; // send a keepalive packet out every 2 seconds (after the 5 second idle period)
setsockopt(fd, SOL_TCP, TCP_KEEPINTVL, &interval, sizeof(interval));
I've been facing similar problems with a QT client app. Basically I handle it with Timers, signals and slots. When the app starts up, it starts a 4 second checkConnectionTimer. Every 4 seconds the timer expires, if the client socket state != AbstractSocket::Connected or Connecting, it attempt to connect with clientSocket->connectToHost
When the socket signals "connected()", it starts a 5 second server heartbeat timer. The server should send a one byte heartbeat message to its clients every 4 seconds. When I get the heartbeat (or any type of message signaled by readyRead()), I restart the heartbeat timer. So if the heartbeat timer ever has a timeout, I assume the connection to be down and it calls clientSocket->disconnectFromHost ();
This is working very well for all different kinds of disconnects on the server, graceful or otherwise (yanking cable). Yes it requires custom heartbeat type of stuff, but at the end of the day it was the quickest and most portable solution.
I wasn't to keen on setting KEEPALIVE timeouts in the kernel. This way its more portable.
In the constructor:
connect(clientSocket, SIGNAL(readyRead()), this, SLOT(readMessage()));
connect(clientSocket, SIGNAL(connected()), this, SLOT(socketConnected()));
connect(clientSocket, SIGNAL(disconnected()), this, SLOT(socketDisconnected()));
connect(heartbeatTimer, SIGNAL(timeout()), this, SLOT(serverTimeout()));
...
// Other Methods
void NetworkClient::checkConnection(){
if (clientSocket->state() != QAbstractSocket::ConnectedState &&
clientSocket->state() != QAbstractSocket::ConnectingState){
connectSocketToHost(clientSocket, hostAddress, port);
}
}
void NetworkClient::readMessage()
{
// Restart the timer by calling start.
heartbeatTimer->start(5000);
//Read the data from the socket
...
}
void NetworkClient::socketConnected (){
heartbeatTimer->start(5000);
}
void NetworkClient::socketDisconnected (){
prioResponseTimer->stop();
}
void NetworkClient::serverTimeout () {
clientSocket->disconnectFromHost();
}
try this signal slot connection:
connect(this, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
this, SLOT(onStateChanged(QAbstractSocket::SocketState)));
at slot implementation:
void TCPWorker::onStateChanged(QAbstractSocket::SocketState socketState ){
qDebug()<< "|GSTCPWorkerThread::onStateChanged|"<<socketState;
...}
I have the same problem, but instead your problem ( always connected ), i have delay 4-5 seconds to receive disconnect signals, after unplugget ethernet wire.
Still looking solution, post answer if find.
try my template of client in Qt:
class Client: public QTcpSocket {
Q_OBJECT
public:
Client(const QHostAddress&, int port, QObject* parent= 0);
~Client();
void Client::sendMessage(const QString& );
private slots:
void readyRead();
void connected();
public slots:
void doConnect();
};
on cpp:
void Client::readyRead() {
// if you need to read the answer of server..
while (this->canReadLine()) {
}
}
void Client::doConnect() {
this->connectToHost(ip_, port_);
qDebug() << " INFO : " << QDateTime::currentDateTime()
<< " : CONNESSIONE...";
}
void Client::connected() {
qDebug() << " INFO : " << QDateTime::currentDateTime() << " : CONNESSO a "
<< ip_ << " e PORTA " << port_;
//do stuff if you need
}
void Client::sendMessage(const QString& message) {
this->write(message.toUtf8());
this->write("\n"); //every message ends with a new line
}
i omitted some code as constructor and slots connections..
try with this and if it doesn t work maybe there is something wrong on server side..
I have a boost async tcp client that need recevive data from server all time.
I want put there a time out that when don't arive data for n sec disconnect from server and try againg to connect.
and I use vc++.
void tcpclient::Connect(){
.....
socket_.async_connect(*iterator,boost::bind(&tcpclient::AfterConnection,shared_from_this(),boost::asio::placeholders::error));
}
void tcpclient::AfterConnection(const boost::system::error_code& error){
if (!error)
{
SetTimeout();
}
}
void tcpclient::SetTimeout(int sec = 1)
{
SOCKET native_sock = socket_.native();
int result = SOCKET_ERROR;
if (INVALID_SOCKET != native_sock)
{
struct timeval tv;
tv.tv_sec = sec;
tv.tv_usec = 0;
result = setsockopt(native_sock, SOL_SOCKET, SO_RCVTIMEO,(char *)&tv,sizeof(struct timeval));
i = GetLastError();
}
}
and I read like blow:
socket_.async_receive(boost::asio::buffer(buffer, 1024),
boost::bind(&tcpClient::handleReceive,
shared_from_this(),
boost::asio::placeholders::error,
buffer,
boost::asio::placeholders::bytes_transferred)
);
but when I try to simulate case that don't arive data connection stay etablished:
$netstat -ao
TCP 192.168.0.6:62836 192.168.0.5:telnet ESTABLISHED 2840
what is the problem why this happend?
Setting SO_RCVTIMEO causes otherwise-blocking calls to read to return with no data after waiting for the specified time, as a non-blocking socket would have done immediately.
So, the question is, what do you, or Boost, do when read returns an EWOULDBLOCK error? You need to show how you're doing the read; if Boost is handling it in an event loop (based on select or poll) it probably just waits for some data to become available.
If that's the case, a better approach is to register a timer callback with the event loop to fire every second or however often, and check whether you received some data during the previous second. The socket options won't help you with that.