Pages

ASIO TCP echo client

Here we are about to write a client for the ASIO TCP echo server described previously.

Its task is giving a way its user to input a line of text that would be sent to the server. Since the server is keeping the connection alive until receives a NUL character, the client should send it after the string, as input by the user, to close the communication.

Once the sending is performed, the client uses the same socket to get the answer from the server.

This post is ancient, June 2011, C++ and ASIO are changed a bit in the meantime, so, on March 2018, I have reviewed post and code. Please follow the link to the newer version.

Here is the client code. Notice it uses an include file, echo.h, that has been already shown, being used by the server (and the main - not shown, since it is embarassingly simple):
#include <iostream>
#include <boost\asio.hpp>
#include "echo.h"

void client()
{
try
{
boost::asio::io_service ios;

boost::asio::ip::tcp::resolver resolver(ios); // 1.
boost::asio::ip::tcp::resolver::query query(boost::asio::ip::tcp::v4(), ECHO_HOST, ECHO_PORT_S);
boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query);

boost::asio::ip::tcp::socket sock(ios); // 2.
sock.connect(*iterator);

std::cout << "Enter message: "; // 3.
std::string request;
getline(std::cin, request);
boost::asio::write(sock, boost::asio::buffer(request));

char data[1] = {'\0'};
boost::asio::write(sock, boost::asio::buffer(data, 1)); // 4.

while(true) // 5.
{
boost::array<char, MSG_LEN> reply;

boost::system::error_code error;
size_t length = sock.read_some(boost::asio::buffer(reply), 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(reply.c_array(), length);
}
std::cout << std::endl; // 6.
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << std::endl;
}
}

1. We use a resolver to find the server socket on the expected host and port.
2. We create a client socket, and connect it to the server one.
3. The client user is asked to input a std::string, we use std::getline() to read it, then we convert it in a ASIO buffer, and write it in the socket.
4. We signal the server we are done, sending a terminator.
5. Now we use the socket to read the feedback from the server. We loop until the communication is closed, reading a chunk of data and outputting that to the standard console.
6. Once the reply is fully received, we add a new line to it.

It could be interesting comparing this client with the one written for the first TCP ASIO client written for a minimal client/server connection. In that case the client did not send any data to the server, it was just a receiver.

But it could be worthy noticing the different approach to the socket connection to the server. Here we check just the first result returned by the resolver, if it is not a "good" connection, an exception is thrown, and the application terminates. The other client is on this aspect more careful. It loops on all the results returned by the resolver looking for the first "good" one.

This post is based on the official documentation Boost ASIO Echo examples.

No comments:

Post a Comment