Related
I have copied the chat-example from the boost examples.
server code:
https://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/example/chat/chat_server.cpp
chat_message.hpp: https://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/example/chat/chat_message.hpp
client code: https://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/example/chat/chat_client.cpp
In chat_server.cpp, I have added a cout in chat_room::leave to get notified when a client leaves. In chat_server, I tried to configure TCP keepalive according to this SO answer:
// additional includes that I have added
#include <winsock2.h>
#include <ws2tcpip.h>
#include <ws2spi.h>
#include <mstcpip.h>
#include <windows.h>
// ----
class chat_server {
public:
chat_server(boost::asio::io_service& io_service,
const tcp::endpoint& endpoint)
: acceptor_(io_service, endpoint),
socket_(io_service) {
do_accept();
}
private:
void do_accept() {
acceptor_.async_accept(socket_,
[this](boost::system::error_code ec) {
if(!ec) {
unsigned long val = 1;
int res = setsockopt(socket_.native_handle(), SOL_SOCKET, SO_KEEPALIVE, (char*) &val, sizeof val);
if(res) std::cout << "Can't set sockopt!" << std::endl;
tcp_keepalive alive;
alive.onoff = TRUE;
alive.keepalivetime = 1000;
alive.keepaliveinterval = 1000;
DWORD bytes_ret = 0;
res = WSAIoctl(socket_.native_handle(), SIO_KEEPALIVE_VALS, &alive, sizeof(alive), NULL, 0,
&bytes_ret, NULL, NULL);
if(res) std::cout << "Can't set TCP keepalive!" << std::endl;
std::make_shared<chat_session>(std::move(socket_), room_)->start();
}
do_accept();
});
}
tcp::acceptor acceptor_;
tcp::socket socket_;
chat_room room_;
};
My test setup is to run the server on my local machine. The client runs on a "VMware Workstation 15 Player"-virtual machine, where NAT is used as network adapter. When I connect to the server and uncheck the "Connected"-checkbox in Virtual Machine Settings (should be the same as unplugging the network cable), I would expect to see the output of chat_room::leave in the console, but it seems, that the server even after a few minutes thinks that the client is still connected.
How can I configure the TCP keepalive appropriately? (I would prefer a cross-platform solution which works on Linux too, but if it works on windows, it's better than nothing)
Edit: I have monitored the sent data with Wireshark and found out that no keep-alive packets were sent. What could cause this?
I have a program that sends and receives broadcast messages. If I run two copies of these programs on the same PC, everything works just fine. If I run each copy on different PCs, then the broadcast messages are not received. I utilized Wireshark to verify whether the packets were sent (yes they were). In addition, on PC "A" Wireshark does not observe the sent packets, but on PC "B" everything is OK. Could the problem be in hardware?
Receiver code:
Receiver::Receiver(QObject *parent) : QObject(parent)
{
udpSocket = new QUdpSocket(this);
udpSocket->bind(45454, QUdpSocket::ShareAddress);
timer = new QTimer(this);
timer->start(500);
connect(timer, SIGNAL(timeout()), this, SLOT(processPendingDatagrams()));
}
void Receiver::processPendingDatagrams()
{
qDebug("first entrance");
while (udpSocket->hasPendingDatagrams()) {
QByteArray datagram;
datagram.resize(udpSocket->pendingDatagramSize());
udpSocket->readDatagram(datagram.data(), datagram.size());
qDebug() << datagram.data();
qDebug("Receive");
sendToQML(datagram.data());
}
}
Sender code:
Sender::Sender(QObject *parent) : QObject(parent)
{
messageNo = 0;
udpSocket = new QUdpSocket(this);
}
void Sender::broadcastDatagram(int message)
{
QByteArray datagram = QByteArray::number(message);
udpSocket->writeDatagram(datagram.data(), datagram.size(),
QHostAddress::Broadcast, 45454);
}
void Sender::sendBroadcast(int message)
{
qDebug() << message;
broadcastDatagram(message);
}
UPDATE
I managed to send and receive packets through an ethernet connection (via a cable).
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
The below code has a TCP client in C and TCP Server in Qt C++. My problem is that I am using TCP for reliability, but it has data losses (not packet). In my main code, if I run tcp client to send data, TCP server receives only one packet. if I add sleep(1); to the client between each packet transfer, then TCP server receives data. Both client and server runs on the same computer.
To simplify the question and can't put too huge code here, I have the below code that performs faster, but it losses last 10-15 bytes of the packet.
TCP C client
main.c
#include "socket_handler.h" //I didn't put the all includes here
#define PORT 22208
//tcp server
int main(void)
{
int sockfd;
uint32_t senderAddress = 2130706433; //127.0.0.1
if( connect_to_server_w_uint( &sockfd, senderAddress, PORT ) < 0 ){
printf("error at line 454\n");
exit(1);
}
char data[] = "124b00068c158f$321$52712304$13.212779$0$O$0$0$b4$1$0$3$0$0$0$0$11$0$7$0$1$fe$f1$aaa9fffffffffd80$2132b00$eb460b5e$1$1$2016-02-22 03:01:00$0000-00-00 00:00:00$321$24754$321$13132$1$98$0$5.1$0$3c$64$1$96$4d$3e8$38$2$46$dc$4$3$f6$e6$17$0$e6$d3$1$0$e6$d3$2$0£";
char buffer[512];
int i=0;
for(i=0; i<1000; i++){
bzero(buffer, 512);
sprintf(buffer, "%d***%s -----",i,data);
send_data_to_server(&sockfd, buffer, strlen(data) +1 );
printf("[%d]: data is sent\n", i);
}
close_connection(&sockfd);
return 0;
}
socket_handler.c
int connect_to_server(int *sockfd , struct in_addr senderAddress, uint16_t destPort){
struct sockaddr_in serv_addr;
*sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (*sockfd < 0)
//error("ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr = senderAddress;
serv_addr.sin_port = htons(destPort);
if (connect( *sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0){
printf("connection error line 1413\n");
close( *sockfd );
return -1;
}
return 0;
}
int connect_to_server_w_uint(int *sockfd, uint32_t senderAddress, uint16_t destPort){
struct sockaddr_in serv_addr;
*sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (*sockfd < 0){
printf("ERROR opening socket");
close(*sockfd);
return -1;
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(senderAddress);
serv_addr.sin_port = htons(destPort);
if (connect(*sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0)
{
printf("ERROR connecting");
close(*sockfd);
return -1;
}
return 0;
}
int send_data_to_server(int *sockfd, char *message, uint16_t msgLength){
int n = write(*sockfd, message, msgLength);
if (n < 0){
printf("ERROR writing to socket");
return -1;
}
return 0;
}
int close_connection(int *sockfd){
close( *sockfd );
return 0;
}
Qt C++ TCP Server
MainWindow.cpp
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void ParseThePacket(QByteArray data);
private:
Ui::MainWindow *ui;
Server *server;
};
Client.h
class Client : public QObject
{
Q_OBJECT
public:
explicit Client(QObject *parent = 0);
public slots:
bool connectToHost(QString host);
bool writeData(QByteArray data);
private:
QTcpSocket *socket;
};
Server.cpp
Server::Server(QObject *parent) : QObject(parent)
{
server = new QTcpServer(this);
connect(server, SIGNAL(newConnection()), this, SLOT(newConnection()));
if( server->listen(QHostAddress::Any, PORT) ){
qDebug() << "tcp server started!";
}else{
qDebug() << "tcp server couldn't start listening";
}
}
void Server::newConnection()
{
qDebug() << "new connection";
while (server->hasPendingConnections())
{
socket = server->nextPendingConnection();
connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected()));
}
}
void Server::disconnected()
{
qDebug() << "disconnected";
socket->deleteLater();
}
void Server::readyRead()
{
qDebug() << "readyRead";
QByteArray buffer = socket->readAll();
emit dataReceived(buffer);
}
Here is an example output from the TCP server(the end of qDebug() output):
00:00:00$321$24754$321$13132$1$98$0$5.1$0$3c$64$1$96$4d$3e8$38$2$46$dc$4$3$f6$e6$17$0$e6$d3$1$0$e6$d3$996***124b00068c158f$321$52712304$13.212779$0$O$0$0$b4$1$0$3$0$0$0$0$11$0$7$0$1$fe$f1$aaa9fffffffffd80$2132b00$eb460b5e$1$1$2016-02-22
03:01:00$0000-00-00
00:00:00$321$24754$321$13132$1$98$0$5.1$0$3c$64$1$96$4d$3e8$38$2$46$dc$4$3$f6$e6$17$0$e6$d3$1$0$e6$d3$997***124b00068c158f$321$52712304$13.212779$0$O$0$0$b4$1$0$3$0$0$0$0$11$0$7$0$1$fe$f1$aaa9fffffffffd80$2132b00$eb460b5e$1$1$2016-02-22
03:01:00$0000-00-00
00:00:00$321$24754$321$13132$1$98$0$5.1$0$3c$64$1$96$4d$3e8$38$2$46$dc$4$3$f6$e6$17$0$e6$d3$1$0$e6$d3$998***124b00068c158f$321$52712304$13.212779$0$O$0$0$b4$1$0$3$0$0$0$0$11$0$7$0$1$fe$f1$aaa9fffffffffd80$2132b00$eb460b5e$1$1$2016-02-22
03:01:00$0000-00-00
00:00:00$321$24754$321$13132$1$98$0$5.1$0$3c$64$1$96$4d$3e8$38$2$46$dc$4$3$f6$e6$17$0$e6$d3$1$0$e6$d3$999***124b00068c158f$321$52712304$13.212779$0$O$0$0$b4$1$0$3$0$0$0$0$11$0$7$0$1$fe$f1$aaa9fffffffffd80$2132b00$eb460b5e$1$1$2016-02-22
03:01:00$0000-00-00
00:00:00$321$24754$321$13132$1$98$0$5.1$0$3c$64$1$96$4d$3e8$38$2$46$dc$4$3$f6$e6$17$0$e6$d3$1$0$e6$d3$"
disconnected
Question 1
Comparing to the original message, it misses "1$0$e6$d3$2$0£" part of the (14 byte) sent data. What is the reason of the missing message? How to fix the code that the TCP server receives the complete data.
Question 2
As I mentioned in the beginning that I am using the same code as a part of a large code and TCP server receives packets when I put sleep(1) between each packet transmission (otherwise it receives only the first packet). What is the reason of it and how to solve it?
I observed the packet transmission on Wireshark that all the TCP packets are sent successfully, but it seems like the receive part has an issue.
I am using Ubuntu 15.04, kernel 3.19.0-69-generic, gcc version 4.9.2
int n = write(*sockfd, message, msgLength);
if (n < 0){
You are only checking that write() did not return a negative value, indicating an error.
However, a write() to a socket does not guarantee that all requested bytes will be written. write() on a socket may return a positive value, fewer than msgLength here, indicating that fewer than the requested bytes have been written. This is documented, in detail, in write()'s manual page.
You are ignoring this possibility, and that's the likely reason you're missing your data. It's up to you to figure out what to do, in this case. The usual approach is to simply go back and attempt to write the remaining bytes (which, again, may not be written in their entirety).
Similarly, when reading from a socket, you are not guaranteed that everything that was written to the socket, by the sender, will be read in one gulp. It is up to you to verify that your reader has read everything that there is to read, and if the reader expects more data, continue reading from the socket until it is received.
readAll just reads all data available to the current moment.
I am using boost::asio::deadline_timer to add socket timeout option. I have implemented Asynchronous HTTP read, and I start the deadline_timer when I start connecting with the server and on every callback I reset the deadline_timer with function deadline_timer::expires_from_now. In the error handler of the deadline_timer I am clearly checking if the timeout was actual or operation_aborted. But almost always I receive actual timeout even before expected timeout. Please have a look at my given code. I don't understand in every callback I am resetting the timer then why I am getting this timeout error.
#define TCP_SOCKET_TIMEOUT 10
Http::AsyncDownload::AsyncDownload(boost::asio::io_service& io_service,
const std::string &protocol,
const std::string &serverip,
const std::string &port,
const std::string &path,
const std::string &filename,
const std::string &localFilePath,
const std::string &username,
const std::string &password) :
resolver_(io_service),
socket_(io_service),
timer_(io_service, boost::posix_time::seconds(TCP_SOCKET_TIMEOUT)),
localFilePath_(localFilePath),
downloadFile_(filename),
protocol_(protocol)
{
........
// Start TCP Socket Timer
start_socket_timer();
// Start an asynchronous resolve to translate the server and service names
// into a list of endpoints.
tcp::resolver::query query(serverip, port);
resolver_.async_resolve(query, boost::bind(&AsyncDownload::resolve, this,
boost::asio::placeholders::error,
boost::asio::placeholders::iterator)
);
}
void Http::AsyncDownload::resolve(const boost::system::error_code &err,
tcp::resolver::iterator endpoint_iterator)
{
// Ok, we have received one packet, so refresh the socket timer
refresh_socket_timer();
if ( !err ) {
.........
boost::asio::async_connect(ssocket_->lowest_layer(), endpoint_iterator, boost::bind(&AsyncDownload::connect, this, boost::asio::placeholders::error));
} else {
// Error handling here
}
}
void Http::AsyncDownload::connect(const boost::system::error_code& err)
{
// Ok, we have received one packet, so refresh the socket timer
refresh_socket_timer();
if ( !err ) {
.........
boost::asio::async_write(socket_, request_,
boost::bind(&AsyncDownload::write_request, this, boost::asio::placeholders::error));
}
else {
// Error handling here
}
}
void Http::AsyncDownload::hand_shake(const boost::system::error_code& err)
{
// Ok, we have received one packet, so refresh the socket timer
refresh_socket_timer();
if ( !err ) {
.........
boost::asio::async_write(*ssocket_, request_,
boost::bind(&AsyncDownload::write_request, this,
boost::asio::placeholders::error));
} else {
// Error handling here.
}
}
void Http::AsyncDownload::write_request(const boost::system::error_code& err)
{
// Ok, we have received one packet, so refresh the socket timer
refresh_socket_timer();
if ( !err ) {
.............
boost::asio::async_read_until(*ssocket_, response_, "\r\n",
boost::bind(&AsyncDownload::read_status_line, this,
boost::asio::placeholders::error));
} else {
// Error handling here
}
}
void Http::AsyncDownload::read_status_line(const boost::system::error_code& err)
{
// Ok, we have received one packet, so refresh the socket timer
refresh_socket_timer();
if ( !err ) {
..........
boost::asio::async_read_until(*ssocket_, response_, "\r\n\r\n",
boost::bind(&AsyncDownload::read_headers, this,
boost::asio::placeholders::error));
} else {
// Error handling here.
}
}
void Http::AsyncDownload::read_headers(const boost::system::error_code& err)
{
refresh_socket_timer();
if ( !err ) {
..............
boost::asio::async_read(*ssocket_, response_,
boost::asio::transfer_at_least(1),
boost::bind(&AsyncDownload::read_content, this,
boost::asio::placeholders::error)
);
} else {
// Error handling here
}
}
void Http::AsyncDownload::read_content(const boost::system::error_code& err)
{
// Ok, we have received one packet, so refresh the socket timer
refresh_socket_timer();
if ( !err ) {
boost::asio::async_read(*ssocket_, response_,
boost::asio::transfer_at_least(1),
boost::bind(&AsyncDownload::read_content, this,
boost::asio::placeholders::error)
);
} else if ( err != boost::asio::error::eof ) {
// Error handling here.
} else {
// We have an EOF
}
}
void Http::AsyncDownload::start_socket_timer()
{
timer_.async_wait(boost::bind(&Http::AsyncDownload::socket_timeout, this,
boost::asio::placeholders::error));
}
void Http::AsyncDownload::refresh_socket_timer()
{
timer_.expires_from_now(boost::posix_time::seconds(TCP_SOCKET_TIMEOUT));
timer_.async_wait(boost::bind(&Http::AsyncDownload::socket_timeout, this, boost::asio::placeholders::error));
}
void Http::AsyncDownload::socket_timeout(const boost::system::error_code &error_)
{
// operation_aborted error is thrown whenever we cancel the timer or
// we reset the timer using expires_from_now function,
if ( error_ != boost::asio::error::operation_aborted ) {
csputils::Utils::DEBUG_MSG(downloadFile_, __LINE__, " ------------> TCP Connection Timeout. Broken Connection Found. Abort Operation ");
// Ok, our TCP connection is broken, we will cancel all asynchronous
// operations of our sockets.
ssocket_->shutdown(); // For Secure Socket & socket.close(); for normal socket.
} else {
// Ok, we have reset the timer, please continue...
}
}
Ok. In the above code you will notice I am starting the timer in the constructor, and once I receive one packet I am refreshing the timer with expries_from_now function call. This call will call error handler (socket_timeout) with the error code operation_aborted, but for every actual timeout this function will be called without operation_aborted and you can see I am checking operation_aborted explicitly, but still as per my expectation I am receiving timeout early, though I am refreshing the timer on every packet I receive but I am sure it is being expired before 10 seconds. I also tried with timeout value = 60 but same effect. Any thoughts.
UPDATE
Updated my code with error handling I have used in my actual code. I have trimmed down my actual code for the sake of simplicity. You can notice in timer timeout handler, I am checking if the timeout was not explicit (i.e operation_aborted), then close the socket. Once the socket will be closed I will get an exception in my socket data handler (mostly read_content function). In that function when I receive exception my socket will exit calling the AsyncDownload destructor where I am doing some more cleaning. My download code works perfect if I remove deadline_timer. I have added it here to detect unforeseen TCP connection drops. I am running this code on embedded Linux on ARM architecture, and my sockets are secure but as I have mentioned my code works perfect without timer so I don't think the problem has something to do with sockets.
Okay, so, I've played with your example hands on.
I can see an infinite loop happening when the timeout has expired, because there is a lack of error handling, and the read_content loop simply continues despite the fact that the timeout had been reached.
Note:
the first read_until_async suggests that it will only read the statusline. This is simply not the case!
See boost read_until does not stop at delimiter.
It will read the first "swoop" of data that includes a minimum of \r\n once. In practice, many servers send the headers in the same packet. (In fact, effective behaviour might depend on proxies and possibly hardware). So, it's not safe to assume that you should always require the second read_until_async to read the headers. And since another "\r\n\r\n" might never happen, it's easy to get into failure mode (when e.g. end-of-stream is reached).
If you don't carefully watch the flow, it's possible to conclude that "the timer fires too early" (because you land in refresh_socket_timer, for example). However, what is happening in my error situation is that read_until_async simply immediately returns, which is erronously treated as if a packet was returned.
So I propose something like
void read_content(const boost::system::error_code& err)
{
if (err && socket_.is_open())
{
DEBUG_TRACE();
boost::asio::async_read(*ssocket_, response_,
boost::asio::transfer_at_least(1),
boost::bind(&AsyncDownload::read_content, this,
boost::asio::placeholders::error)
);
refresh_socket_timer();
}
else
std::cerr << "Error '" << err.message() << "'\n";
}
So we avoid the infinite loop on connection dropped.
void refresh_socket_timer()
{
if (socket_.is_open())
{
DEBUG_TRACE();
timer_.expires_from_now(boost::posix_time::seconds(TCP_SOCKET_TIMEOUT));
timer_.async_wait(boost::bind(&AsyncDownload::socket_timeout, this, boost::asio::placeholders::error));
}
}
So we avoid refreshing the timer after the socket has been closed.
void socket_timeout(const boost::system::error_code &error_)
{
// operation_aborted error is thrown whenever we cancel the timer or
// we reset the timer using expires_from_now function,
if ( error_ != boost::asio::error::operation_aborted ) {
DEBUG_TRACE();
std::cout << " ------------> TCP Connection Timeout. Broken Connection Found. Abort Operation\n";
// Ok, our TCP connection is broken, we will cancel all asynchronous
// operations of our sockets.
socket_.close();
}
}
So we actively close the socket on timeout.
If you comment the if(...) conditionals out in the above, you'd see the failure mode I was describing.
Here's the full example I used to test:
#include <boost/asio.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/bind.hpp>
using tcp = boost::asio::ip::tcp;
#define TCP_SOCKET_TIMEOUT 2
#define DEBUG_TRACE() do { std::cout << __FILE__ << ':' << __LINE__ << "\t" << __FUNCTION__ << "\n"; } while(false)
struct AsyncDownload
{
tcp::resolver resolver_;
tcp::socket socket_;
tcp::socket* ssocket_ = &socket_;
boost::asio::deadline_timer timer_;
std::string localFilePath_;
boost::asio::streambuf response_;
AsyncDownload(boost::asio::io_service& io_service,
const std::string &protocol,
const std::string &serverip,
const std::string &port) :
resolver_(io_service),
socket_(io_service),
timer_(io_service, boost::posix_time::seconds(TCP_SOCKET_TIMEOUT))
{
DEBUG_TRACE();
// Start TCP Socket Timer
start_socket_timer();
// Start an asynchronous resolve to translate the server and service names
// into a list of endpoints.
tcp::resolver::query query(serverip, port);
resolver_.async_resolve(query, boost::bind(&AsyncDownload::resolve, this,
boost::asio::placeholders::error,
boost::asio::placeholders::iterator)
);
}
void resolve(const boost::system::error_code &err, tcp::resolver::iterator endpoint_iterator)
{
DEBUG_TRACE();
boost::asio::async_connect(ssocket_->lowest_layer(), endpoint_iterator, boost::bind(&AsyncDownload::connect, this, boost::asio::placeholders::error));
refresh_socket_timer();
}
void connect(const boost::system::error_code& err)
{
DEBUG_TRACE();
std::string const request_ = "GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n";
boost::asio::async_write(socket_, boost::asio::buffer(request_),
boost::bind(&AsyncDownload::write_request, this, boost::asio::placeholders::error));
refresh_socket_timer();
}
void write_request(const boost::system::error_code& err)
{
DEBUG_TRACE();
boost::asio::async_read_until(*ssocket_, response_, "\r\n",
boost::bind(&AsyncDownload::read_status_line, this,
boost::asio::placeholders::error));
refresh_socket_timer();
}
void read_status_line(const boost::system::error_code& err)
{
DEBUG_TRACE();
std::cout << "read_status_line: " << &response_ << "\n";
boost::asio::async_read_until(*ssocket_, response_, "\r\n\r\n",
boost::bind(&AsyncDownload::read_headers, this,
boost::asio::placeholders::error));
refresh_socket_timer();
}
void read_headers(const boost::system::error_code& err)
{
DEBUG_TRACE();
// ..............
boost::asio::async_read(*ssocket_, response_,
boost::asio::transfer_at_least(1),
boost::bind(&AsyncDownload::read_content, this,
boost::asio::placeholders::error)
);
refresh_socket_timer();
}
void read_content(const boost::system::error_code& err)
{
if (err && socket_.is_open())
{
DEBUG_TRACE();
boost::asio::async_read(*ssocket_, response_,
boost::asio::transfer_at_least(1),
boost::bind(&AsyncDownload::read_content, this,
boost::asio::placeholders::error)
);
refresh_socket_timer();
}
else
std::cerr << "Error '" << err.message() << "'\n";
}
void start_socket_timer()
{
DEBUG_TRACE();
timer_.async_wait(boost::bind(&AsyncDownload::socket_timeout, this, boost::asio::placeholders::error));
}
void refresh_socket_timer()
{
if (socket_.is_open())
{
DEBUG_TRACE();
timer_.expires_from_now(boost::posix_time::seconds(TCP_SOCKET_TIMEOUT));
timer_.async_wait(boost::bind(&AsyncDownload::socket_timeout, this, boost::asio::placeholders::error));
}
}
void socket_timeout(const boost::system::error_code &error_)
{
// operation_aborted error is thrown whenever we cancel the timer or
// we reset the timer using expires_from_now function,
if ( error_ != boost::asio::error::operation_aborted ) {
DEBUG_TRACE();
std::cout << " ------------> TCP Connection Timeout. Broken Connection Found. Abort Operation\n";
// Ok, our TCP connection is broken, we will cancel all asynchronous
// operations of our sockets.
socket_.close();
}
}
};
int main()
{
DEBUG_TRACE();
boost::asio::io_service io_service;
AsyncDownload download(
io_service,
"http",
"www.google.com",
"80");
io_service.run();
}
http://www.boost.org/doc/libs/1_46_0/doc/html/boost_asio/example/chat/chat_client.cpp
I am working on client application based on he example above.
I wanted to do the client connection in separte thread so that UI doesnot get stuck.Here UI is getiing stuck.
1. Can you tell me how to acheive this?
2. what is the meaning of the this line?
boost::thread t(boost::bind(&boost::asio::io_service::run, &io_service));
t.join();
Is this line create the separate thread for connection?
client::client(boost::asio::io_service& io_service, tcp::resolver::iterator endpoint_iterator)
: io_service_(io_service),
resolver_(io_service),
socket_(io_service_)
{
tcp::endpoint endpoint = *endpoint_iterator;
socket_.async_connect( endpoint,
boost::bind(&client::handle_connect, this,boost::asio::placeholders::error,
++endpoint_iterator));
}
void client::handle_connect(const boost::system::error_code& error,
tcp::resolver::iterator endpoint_iterator)
{
strcpy(data_,"Hello");
if (!error)
{
/*boost::asio::async_read(socket_,
boost::asio::buffer(data_, MAX_PATH),
boost::bind(&client::handle_read, this,
boost::asio::placeholders::error));*/
boost::asio::async_write(socket_, boost::asio::buffer(data_, MAX_PATH),
boost::bind(&client::handle_read, this,
boost::asio::placeholders::error));
}
else if (endpoint_iterator != tcp::resolver::iterator())
{
socket_.close();
tcp::endpoint endpoint = *endpoint_iterator;
socket_.async_connect( endpoint,
boost::bind(&client::handle_connect, this,
boost::asio::placeholders::error, ++endpoint_iterator));
}
}
void client::handle_read(const boost::system::error_code& error)
{
if (!error)
{
memset(data_,0,MAX_PATH);
boost::asio::async_read( socket_,
boost::asio::buffer(data_, MAX_PATH),
boost::bind(&client::handle_read, this,
boost::asio::placeholders::error));
if (strcmp(data_,"Hello Response")==0)
{
MessageBox(NULL,_T("Regd Done"),_T("Vue"),1);
// return ;
}
}
}
CConnectionMgr::CConnectionMgr(void)
{
}
void CConnectionMgr::Connect()
{
try
{
char* host = "192.168.4.84";
char* port = "55555";
boost::asio::io_service io_service;
tcp::resolver resolver(io_service);
tcp::resolver::query query(tcp::v4(),host , port);
tcp::resolver::iterator iterator = resolver.resolve(query);
c = new client(io_service, iterator);
//boost::thread thrd(boost::bind(&boost::asio::io_service::run, &io_service));
boost::thread t(boost::bind(&boost::asio::io_service::run, &io_service));
t.join();
// MessageBox(NULL,_T("Join"),_T("ff"),1);
}
catch (std::exception& e)
{
CString csMsg(e.what());
MessageBox(NULL,csMsg,_T("ff"),1);
}
}
The "t.join()" waits for the thread 't' to exit. Thread 't' is running the run() method on io_service and will exit when there is no remaining I/O to complete.
So, your Connect() method will block until all the I/O is finished, which is clear not what you want. If you are going to do asynchronous I/O so that your client doesn't block, you need to design a way for your I/O context to communicate with our UI context. It won't happen by magic.
Can you tell me how to acheive this?
You could launch the boost thread in your main i.e. somewhere before you enter the UI event loop (the blocking call) but don't do a join.
Have a look at the HTTP server examples: In one of them it's shown how you can start your io_service in the main and stop it via CTRL-c. In your case you would probably do this using a GUI button or event. Once you call the io_service stop method, you can then do the join on the thread.
what is the meaning of the this line? boost::thread t(boost::bind(&boost::asio::io_service::run, &io_service));
Runs the io_service::run in a new thread
t.join();
Waits for the thread to finish like janm stated which will happen once the io_service runs out of work or once the io_service::stop method is called