I have the following code where I'm trying to send a packet to a specific client by changing the endpoint of the socket manually and I'm not sure how to configure the socket to use the async_write function to send the packet. Lines 44-47 are used to try solving the problem within the boost async server example (modified).
#include <cstdlib>
#include <iostream>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
class session
{
public:
session(boost::asio::io_service& io_service)
: socket_(io_service)
{
}
tcp::socket& socket()
{
return socket_;
}
void start()
{
std::cout<<"start(): "<<std::endl;
socket_.async_read_some(boost::asio::buffer(data_, max_length),
boost::bind(&session::handle_read, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
void read_handler(const boost::system::error_code& ec, std::size_t bytes_transferred);
private:
void handle_read(const boost::system::error_code& error,
size_t bytes_transferred)
{
std::cout<<"handle read: bytes_transferred"<<bytes_transferred<<std::endl;
if (!error)
{
data_ = {'0','1','2','3','4','5','6','7','8','9'};
/*read_handler(error, bytes_transferred);
boost::asio::async_write(socket_,boost::asio::buffer(data_, bytes_transferred),
boost::bind(&session::handle_write, this,
boost::asio::placeholders::error));*/
boost::system::error_code ec;
boost::asio::ip::tcp::endpoint endpoint = socket_.remote_endpoint(ec);
std::cout<<"ip address: "<<endpoint.address()<<std::endl;
std::cout<<"port: "<<endpoint.port()<<std::endl;
//how to get the socket to send data to specific port, ip-address e.g. changing the ip-address and port by editing it?
async_write(socket_, boost::asio::buffer(data_, max_length), boost::bind(&session::writeHandler, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}
else
{
delete this;
}
}
void writeHandler(const boost::system::error_code& errorCode, size_t bytesTransferred)
{
std::cout << "DEBUG> Transfered " << bytesTransferred << " bytes to " << socket_.remote_endpoint().address().to_string() << std::endl;
}
void handle_write(const boost::system::error_code& error)
{
std::cout<<"handle write: "<<std::endl;
if (!error)
{
std::cout<<"before: "<<data_<<std::endl;
socket_.async_read_some(boost::asio::buffer(data_, max_length),
boost::bind(&session::handle_read, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
std::cout<<"after: "<<data_<<std::endl;
}
else
{
delete this;
}
}
tcp::socket socket_;
enum { max_length = 1024 };
char data_[max_length];
};
void session::read_handler(const boost::system::error_code& ec, std::size_t bytes_transferred)
{
std::cout<<bytes_transferred<<std::endl;
}
class server
{
public:
server(boost::asio::io_service& io_service, short port)
: io_service_(io_service),
acceptor_(io_service, tcp::endpoint(tcp::v4(), port))
{
start_accept();
}
private:
void start_accept()
{
session* new_session = new session(io_service_);
acceptor_.async_accept(new_session->socket(),
boost::bind(&server::handle_accept, this, new_session,
boost::asio::placeholders::error));
}
void handle_accept(session* new_session,
const boost::system::error_code& error)
{
if (!error)
{
new_session->start();
}
else
{
delete new_session;
}
start_accept();
}
boost::asio::io_service& io_service_;
tcp::acceptor acceptor_;
};
int main()
{
try
{
boost::asio::io_service io_service;
server s(io_service, 4000);
io_service.run();
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << "\n";
}
return 0;
}
It looks like you are trying to apply some concepts of UDP to a TCP stream.
TCP needs to establish a connection with a 3-way handshake.
For that reason, you can't send data to another client simply by modifying the ip remote endpoint address of a socket.
A TCP server listens for incoming connections, accepts them and at the end of this process has a valid TCP socket where you can write data. Each client has it's own socket. Also note that a TCP socket provides a data stream (not packets/datagrams).
On the other hand, UDP does not have the concept of a connection. You can send datagrams to multiple endpoints using the same UDP socket (boost::asio::ip::udp::socket::send_to)
Related
Just to test my server, I've created 100 requests using a for loop from my client side and while my server is writing response for the Nth request I deliberately pressed control+c from the client, Thats it. The server stops and has gone unresponsive although I try connecting it using a new connection, can any one advice me how to make my server stable and immune to such interrupt.
here is my server:
class tcp_server
{
public:
tcp_server(boost::asio::io_service& io_service)
: acceptor_(io_service, tcp::endpoint(tcp::v4(), 2020))
{
start_accept();
}
private:
void start_accept()
{
tcp_connection::pointer new_connection =
tcp_connection::create(acceptor_.get_io_service());
acceptor_.async_accept(new_connection->socket(),
boost::bind(&tcp_server::handle_accept, this, new_connection,
boost::asio::placeholders::error));
}
void handle_user_read(const boost::system::error_code& err,
std::size_t bytes_transferred)
{
}
void handle_accept(tcp_connection::pointer new_connection,
const boost::system::error_code& error)
{
if (!error)
{
new_connection->start();
start_accept();
}
}
tcp::acceptor acceptor_;
};
here is my tcp connection:
class tcp_connection : public boost::enable_shared_from_this<tcp_connection>
{
public:
typedef boost::shared_ptr<tcp_connection> pointer;
static pointer create(boost::asio::io_service& io_service)
{
return pointer(new tcp_connection(io_service));
}
tcp::socket& socket()
{
return socket_;
}
void start()
{
// Start reading messages from the server
start_read();
}
public:
tcp_connection(boost::asio::io_service& io_service) : socket_(io_service),timer_(io_service), io(io_service),timer2_(io_service)
{
}
// Reading messages from the server
void start_read()
{
boost::asio::async_read(socket_, input_buffer_,
boost::asio::transfer_at_least(1),
boost::bind(&tcp_connection::handle_read, shared_from_this(),
boost::asio::placeholders::error));
timer_.expires_from_now(boost::posix_time::seconds(120));
timer_.async_wait(boost::bind(&tcp_connection::close, shared_from_this()));
}
void close()
{
cout<<"I didn't hear the client yet:closing the socket......"<<endl;
socket_.close();
}
// When stream is received, handle the message from the client
int handle_read(const boost::system::error_code& ec)
{
if (!ec)
{
std::istream is(&input_buffer_);
std::string line;
std::getline(is, line);
messageFromClient_+=line;
messageFromClient_.erase(std::remove(messageFromClient_.begin(), messageFromClient_.end(), '\n'), messageFromClient_.end());
std::size_t found = messageFromClient_.find('\0');
if(found==std::string::npos)
{
boost::asio::async_read(socket_, input_buffer_,
boost::asio::transfer_at_least(1),
boost::bind(&tcp_connection::handle_read, shared_from_this(),
boost::asio::placeholders::error));
}
else{
performmaj();--my logic never mind.
std::cout << "Request: "<<i<<" is on process......"<<"\n";--mylogic
boost::asio::ip::tcp::no_delay option(true);
socket_.set_option(option);
write();
messageToClient_="";--my logic.
boost::system::error_code tc;
socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_send, tc);
}
std::cout << "Request: "<<i<<" completed"<<"\n";
++i;
(boost::asio::io_service io);
}else
{
std::cout << "Error on receive: " << ec.message() << "\n";
}
}
void write()
{
try{
boost::asio::write(socket_,boost::asio::buffer(messageToClient_), boost::asio::transfer_at_least(messageToClient_.size()));
}catch(exception e)
{
cout<<e.what()<<endl;
socket_.close();
io.run();
}
}
please see my below code where i have used async_write; Note the string i have intende to write is of size:11279204. but using async_write in the below code let my client to recieve the meaasage that is more of partial but not complete.
class tcp_connection : public boost::enable_shared_from_this<tcp_connection>
{
public:
typedef boost::shared_ptr<tcp_connection> pointer;
static pointer create(boost::asio::io_service& io_service)
{
return pointer(new tcp_connection(io_service));
}
tcp::socket& socket()
{
return socket_;
}
void start()
{
// Start reading messages from the server
start_read();
}
public:
tcp_connection(boost::asio::io_service& io_service) : socket_(io_service),timer_(io_service), io(io_service),timer2_(io_service)
{
//io=io_service;
}
// Reading messages from the server
void start_read()
{
boost::asio::async_read(socket_, input_buffer_,
boost::asio::transfer_at_least(1),
boost::bind(&tcp_connection::handle_read, shared_from_this(),
boost::asio::placeholders::error));
timer_.expires_from_now(boost::posix_time::seconds(120));
timer_.async_wait(boost::bind(&tcp_connection::close, shared_from_this()));
}
void close()
{
cout<<"I didn't hear the client yet:closing the socket......"<<endl;
socket_.close();
}
// When stream is received, handle the message from the client
int handle_read(const boost::system::error_code& ec)
{
if (!ec)
{
std::istream is(&input_buffer_);
std::string line;
std::getline(is, line);
messageFromClient_+=line;
messageFromClient_.erase(std::remove(messageFromClient_.begin(), messageFromClient_.end(), '\n'), messageFromClient_.end());
std::size_t found = messageFromClient_.find('\0');
if(found==std::string::npos)
{
boost::asio::async_read(socket_, input_buffer_,
boost::asio::transfer_at_least(1),
boost::bind(&tcp_connection::handle_read, shared_from_this(),
boost::asio::placeholders::error));
}
else{
performmaj();
cout<<messageToClient_.size()<<endl;--11279204
try{
boost::asio::async_write(socket_, boost::asio::buffer(messageToClient_.data(),messageToClient_.size()),
// boost::asio::transfer_at_least(messageToClient_.size()),
boost::bind(&tcp_connection::handle_write, shared_from_this(),
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}catch(exception e)
{
Shutdown();
}
}
std::cout << "Request: "<<i<<" completed"<<"\n";
++i;
return 0;
}else
{
std::cout << "Error on receive: " << ec.message() << "\n";
}
}
void Shutdown()
{
try {
socket_.shutdown(socket_.shutdown_both);
socket_.close();
} catch (std::exception &e)
{
std::cout << "Error Closing Socket" << e.what() << std::endl;
}
}
void performmaj()
{
std::size_t found = messageFromClient_.find('\0');
if (found!=std::string::npos)
{
std::cout << "Request: "<<i<<" Recieved"<<"\n";
std::cout << "Request: "<<i<<" is on process......"<<"\n";
if (messageFromClient_.size () > 0) messageFromClient_.resize (messageFromClient_.size () - 1);
messageToClient_=test(messageFromClient_);
messageFromClient_="";
messageToClient_.erase(std::remove(messageToClient_.begin(), messageToClient_.end(), '\n'), messageToClient_.end());
}
}
void handle_write(const boost::system::error_code& ec,
size_t bytes_transferred)
{
boost::asio::async_write(socket_,boost::asio::buffer(messageToClient_.data(),bytes_transferred),
// boost::asio::transfer_at_least(bytes_transferred),
boost::bind(&tcp_connection::handle_write, shared_from_this(),
boost::asio::placeholders::error,
bytes_transferred));
boost::system::error_code tc;
socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_send, tc);
}
tcp::socket socket_;
std::string messageToClient_;
boost::asio::streambuf input_buffer_;
std::string messageFromClient_;
boost::asio::io_service& io;
boost::asio::deadline_timer timer_,timer2_;
};
the above unpredicted behaviour of async_write have caused me to use asio::write.
The boost::asio::write() blocks until the data is written or an exception is thrown. Your write() function catches the exception, closes the socket, and returns, but does not indicate the socket is closed. You then call shutdown on a closed socket. Create a Shutdown function. Catch the drop exception error in write() but wait to call Shutdown after Write() call. Your logic always calls Shutdown() on good or bad writes. Also do not call io.run(). Your io_service() is already running.
Shutdown()
{
try {
socket_.shutdown(socket_.shutdown_both);
socket_->close();
} catch (std::exception &e)
{
std::cout << "Error Closing Socket" << e.what() << std::endl;
}
}
I've modified the UDP client code from Boost daytime client tutorial into the following:
class UDPClient
{
public:
udp::socket* socket;
udp::endpoint* receiver_endpoint;
boost::array<char, 1024> recv_buffer;
UDPClient();
void do_receive();
void handle_receive(const boost::system::error_code& error, size_t);
};
UDPClient::UDPClient()
{
boost::asio::io_service io_service;
udp::resolver resolver(io_service);
udp::resolver::query query(udp::v4(), "127.0.0.1", "8888");
receiver_endpoint = new udp::endpoint(*resolver.resolve(query));
socket = new udp::socket(io_service);
socket->open(udp::v4());
do_receive();
while (true)
{
io_service.poll();
Sleep(1);
}
}
void UDPClient::do_receive()
{
socket->async_receive_from(boost::asio::buffer(recv_buffer), *receiver_endpoint,
boost::bind(&UDPClient::handle_receive, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
void UDPClient::handle_receive(const boost::system::error_code& error, size_t bytes_transferred)
{
cout << "ulala" << endl;
if (!error || error == boost::asio::error::message_size)
do_receive();
}
If all works out according to plan, "ulala" would only be printed if there is an incoming message. However that is not the case here... The handler gets called instantaneously and "ulala" is printed regardless of whether there is an incoming message. I've tried a few different things: swapping io_service.poll() with io_service.run() and io_service.run_one(), as well as removing Sleep(1), but none of those changes have any effect on the problem. What should I do?
Thanks in advance!
socket = new udp::socket(io_service);
socket->open(udp::v4());
sets up a socket for sending to arbitrary endpoints. To receive ("listen"), use
socket = new udp::socket(io_service, udp::endpoint(udp::v4(), 8888));
Besides that, the socket and receiver_endpoint are leaked now. To fix that:
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/array.hpp>
#include <iostream>
using boost::asio::ip::udp;
class UDPClient
{
public:
boost::asio::io_service io_service;
udp::socket socket;
udp::endpoint receiver_endpoint;
boost::array<char, 1024> recv_buffer;
UDPClient();
void do_receive();
void handle_receive(const boost::system::error_code& error, size_t);
};
UDPClient::UDPClient()
: io_service(),
socket(io_service, {udp::v4(), 8888})
{
do_receive();
io_service.run();
}
void UDPClient::do_receive()
{
socket.async_receive_from(boost::asio::buffer(recv_buffer), receiver_endpoint,
boost::bind(&UDPClient::handle_receive, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
void UDPClient::handle_receive(const boost::system::error_code& error, size_t bytes_transferred)
{
std::cout << "ulala" << std::endl;
std::cout << "Received: '" << std::string(recv_buffer.begin(), recv_buffer.begin()+bytes_transferred) << "'\n";
if (!error || error == boost::asio::error::message_size)
do_receive();
}
int main()
{
UDPClient updclient;
}
This also prints the message received (assuming it is printable). See
boost::asio async_receive_from UDP endpoint shared between threads?
for a way to make it possible to handle multiple UDP requests concurrently.
I am trying to make my first TCP server using boost::asio. The server will listen to clients and if it receives message "MESSAGE_SEND_A:", it should send the following message back to the client: "A|A|A|A|A|A". If it receives message "MESSAGE_SEND_B:", then accordingly it should send another message to the client: "B|B|B|B|B|B".
Now, I have been studying the Boost TCP server tutorial and it is more or less clear:
EDIT: Code is rewritten based on comments
#include <ctime>
#include <iostream>
#include <string>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
class tcp_connection : public boost::enable_shared_from_this<tcp_connection>
{
public:
typedef boost::shared_ptr<tcp_connection> pointer;
static pointer create(boost::asio::io_service& io_service)
{
return pointer(new tcp_connection(io_service));
}
tcp::socket& socket()
{
return socket_;
}
void start()
{
// Start reading messages from the server
start_read();
if (messageFromClient_ == "MESSAGEA:")
{
messageToClient_ = "A|A|A|A|A|A|A|A|A|A";
}
else if (messageFromClient_ == "MESSAGEB:")
{
messageToClient_ = "B|B|B|B|B|B|B|B|B|B";
}
boost::asio::async_write(socket_, boost::asio::buffer(messageToClient_),
boost::bind(&tcp_connection::handle_write, shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
private:
tcp_connection(boost::asio::io_service& io_service) : socket_(io_service)
{
}
// Reading messages from the server
void start_read()
{
// Start an asynchronous operation to read a newline-delimited message.
// When read, handle_read should kick in
boost::asio::async_read(socket_, input_buffer_,
boost::asio::transfer_at_least(1),
boost::bind(&tcp_connection::handle_read, this,
boost::asio::placeholders::error));
}
// When stream is received, handle the message from the client
void handle_read(const boost::system::error_code& ec)
{
//if (stopped_)
// return;
// Making the message nil every time the function starts. Do I need it???????
messageFromClient_ = "";
if (!ec)
{
// Extract the newline-delimited message from the buffer.
std::string line;
std::istream is(&input_buffer_);
std::getline(is, line);
// Empty messages are heartbeats and so ignored.
if (!line.empty())
{
messageFromClient_ = line;
std::cout << "Received: " << line << "\n";
}
start_read();
}
else
{
std::cout << "Error on receive: " << ec.message() << "\n";
}
}
void handle_write(const boost::system::error_code& /*error*/,
size_t /*bytes_transferred*/)
{
}
tcp::socket socket_;
std::string messageToClient_;
boost::asio::streambuf input_buffer_;
std::string messageFromClient_;
};
class tcp_server
{
public:
tcp_server(boost::asio::io_service& io_service)
: acceptor_(io_service, tcp::endpoint(tcp::v4(), 7767))
{
start_accept();
}
private:
void start_accept()
{
tcp_connection::pointer new_connection =
tcp_connection::create(acceptor_.get_io_service());
acceptor_.async_accept(new_connection->socket(),
boost::bind(&tcp_server::handle_accept, this, new_connection,
boost::asio::placeholders::error));
}
void handle_user_read(const boost::system::error_code& err,
std::size_t bytes_transferred)
{
}
void handle_accept(tcp_connection::pointer new_connection,
const boost::system::error_code& error)
{
if (!error)
{
new_connection->start();
start_accept();
}
}
tcp::acceptor acceptor_;
};
int main()
{
try
{
boost::asio::io_service io_service;
tcp_server server(io_service);
io_service.run();
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
}
return 0;
}
The code is compiled well on Qt, but gives me:
Error on receive: Operation canceled
every time I am trying to send a message from my client (iPad).
Thank you!
the function start() should asynchronously read from the socket, while invoking handle_read() function when data received.
Please review this example:
http://www.boost.org/doc/libs/1_45_0/doc/html/boost_asio/example/timeouts/async_tcp_client.cpp
Basically I have a client where I send a string of 10 bytes hellohello to a server and within the server I expect the reply to be 0123456789 back to the client but instead I get hellohello again? I changed the char data_ to char data_out on line 58 in the tcp_server.cpp because I thought that was the place to send packet data out? I'm pretty sure that gets called but for some reason things aren't working like I thought.
This is the server output,
handle read: bytes_transferred10
10
handle write:
0123456789
handle read: bytes_transferred0
I also wonder why did handle read: bytes_transferred0 get called again?
This is the client output,
Enter message: hellohello
Reply is: hellohello
Process returned 0 (0x0) execution time : 6.484 s
Press any key to continue.
This is the tcp_server.cpp
#include <cstdlib>
#include <iostream>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
class session
{
public:
session(boost::asio::io_service& io_service)
: socket_(io_service)
{
}
tcp::socket& socket()
{
return socket_;
}
void start()
{
socket_.async_read_some(boost::asio::buffer(data_, max_length),
boost::bind(&session::handle_read, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
void read_handler(const boost::system::error_code& ec, std::size_t bytes_transferred);
private:
void handle_read(const boost::system::error_code& error,
size_t bytes_transferred)
{
std::cout<<"handle read: bytes_transferred"<<bytes_transferred<<std::endl;
if (!error)
{
read_handler(error, bytes_transferred);
boost::asio::async_write(socket_,
boost::asio::buffer(data_, bytes_transferred),
boost::bind(&session::handle_write, this,
boost::asio::placeholders::error));
}
else
{
delete this;
}
}
void handle_write(const boost::system::error_code& error)
{
std::cout<<"handle write: "<<std::endl;
data_out = {'0','1','2','3','4','5','6','7','8','9'};
if (!error)
{
std::cout<<data_out<<std::endl;
socket_.async_read_some(boost::asio::buffer(data_out, max_length),
boost::bind(&session::handle_read, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
else
{
delete this;
}
}
tcp::socket socket_;
enum { max_length = 1024 };
char data_[max_length];
char data_out[max_length];
};
void session::read_handler(const boost::system::error_code& ec, std::size_t bytes_transferred)
{
std::cout<<bytes_transferred<<std::endl;
}
class server
{
public:
server(boost::asio::io_service& io_service, short port)
: io_service_(io_service),
acceptor_(io_service, tcp::endpoint(tcp::v4(), port))
{
start_accept();
}
private:
void start_accept()
{
session* new_session = new session(io_service_);
acceptor_.async_accept(new_session->socket(),
boost::bind(&server::handle_accept, this, new_session,
boost::asio::placeholders::error));
}
void handle_accept(session* new_session,
const boost::system::error_code& error)
{
if (!error)
{
new_session->start();
}
else
{
delete new_session;
}
start_accept();
}
boost::asio::io_service& io_service_;
tcp::acceptor acceptor_;
};
int main()
{
try
{
boost::asio::io_service io_service;
server s(io_service, 4000);
io_service.run();
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << "\n";
}
return 0;
}
tcp_client.cpp
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
enum { max_length = 1024 };
int main(int argc, char* argv[])
{
try
{
boost::asio::io_service io_service;
tcp::resolver resolver(io_service);
tcp::resolver::query query(tcp::v4(), "127.0.0.1", "4000");
tcp::resolver::iterator iterator = resolver.resolve(query);
tcp::socket s(io_service);
s.connect(*iterator);
using namespace std; // For strlen.
std::cout << "Enter message: ";
char request[max_length];
std::cin.getline(request, max_length);
size_t request_length = strlen(request);
boost::asio::write(s, boost::asio::buffer(request, request_length));
char reply[max_length];
size_t reply_length = boost::asio::read(s,boost::asio::buffer(reply, request_length));
std::cout << "Reply is: ";
std::cout.write(reply, reply_length);
std::cout << "\n";
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << "\n";
}
return 0;
}
Your comment
I think handle_read() calls handle_write() recursively?
is close but not quite correct as there is no recursion here. The documentation explains this nicely:
Regardless of whether the asynchronous operation completes immediately
or not, the handler will not be invoked from within this function.
Invocation of the handler will be performed in a manner equivalent to
using boost::asio::io_service::post().
Added emphasis is mine. Instead of recursion, It is better to think of these concepts as chaining since one operation such as async_write() is initiated in the handler of another, such as async_read(). The exact specifics depend on the protocol in use.
If you want the server to send the string 0123456789 to the client, fill your buffer before invoking async_write().
I have a problem, i have a TCP connection between a client and a server , when the client initialize he send a message to the server and the serveur answer by a welcom message .
All this work fine on a local network.
So my problem is that I use async_write and async_read ( because I need my server to be asynchronous )
My client send the message to the server , the server see it and answer but my client never get the welcom message .
Otherwise when I close my server , the client received the welcome message .
here is my server code :
main.cpp
int main()
{
try
{
boost::asio::io_service io_service;
tcp_server server(io_service, 7171);
io_service.run();
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
}
return 0;
}
tcp_server
class tcp_server
{
public:
tcp_server(boost::asio::io_service& io_service, int port) // (1)
: m_acceptor(io_service, tcp::endpoint(tcp::v4(), port))
{
std::cout << "Port : " << port << std::endl;
start_accept();
}
private:
void start_accept()
{
tcp_connection::pointer new_connection = tcp_connection::create(m_acceptor.io_service());
m_acceptor.async_accept(new_connection->socket(),
boost::bind(&tcp_server::handle_accept, this, new_connection,
boost::asio::placeholders::error));
}
void handle_accept(tcp_connection::pointer new_connection, const boost::system::error_code& error) // (4)
{
if (!error)
{
std::cout << "Get one client!" << std::endl;
new_connection->start();
start_accept(); // (5)
}
}
tcp::acceptor m_acceptor;
};
tcp_connection
class tcp_connection : public boost::enable_shared_from_this<tcp_connection>
{
public:
typedef boost::shared_ptr<tcp_connection> pointer;
static pointer create(boost::asio::io_service& ios)
{
pointer new_connection(new tcp_connection(ios) );
return new_connection;
}
tcp::socket& socket()
{
return m_socket;
}
void do_read() // (1)
{
boost::asio::async_read(m_socket, boost::asio::buffer(m_buffer), // (3)
boost::bind(&tcp_connection::handle_read, shared_from_this(),
boost::asio::placeholders::error)
);
}
void start()
{
m_message = "Welcome on the server \n";
boost::asio::async_write(m_socket, boost::asio::buffer(m_message),
boost::bind(&tcp_connection::handle_write, shared_from_this(),
boost::asio::placeholders::error)
);
}
private:
tcp_connection(boost::asio::io_service& io_service)
: m_socket(io_service)
{ }
void handle_write(const boost::system::error_code& error)
{
std::cout << "handle_write : "<< m_message << std::endl;
if (!error)
do_read(); // (2)
else
std::cout << error.message() << std::endl;
}
void handle_read(const boost::system::error_code& error) // (6)
{
std::cout << "handle read" << m_buffer.data() <<std::endl;
if (!error)
do_read();
else
close();
}
void close() // (7)
{
m_socket.close();
}
tcp::socket m_socket;
std::string m_message;
boost::array<char, 128> m_buffer;
};
I don't understand why ?
And How can I avoid this ?
Please, the manual of async_read:
This function is used to asynchronously read a certain number of bytes
of data from a stream. The function call always returns immediately.
The asynchronous operation will continue until one of the following
conditions is true:
The supplied buffers are full. That is, the bytes transferred is equal to the sum of the buffer sizes.
An error occurred.
In your case, none of the 2 conditions are satisfied - until the peer closes the socket.
You should use async_read_some instead (or async_read_until, but it might be a bit more complicated).