Boost::asio Blocking Tcp Server confusion - c++

I have been stuck with this prolem for the past 5 hours or so.. Sorry if the question is too obvious/noob but I am noob myself when it comes to boost::asio or tcp/ip in general.
So here is the problem. I am trying to modify the blocking tcp server example :
void session(socket_ptr sock)
{
try
{
for (;;)
{
char data[max_length];
boost::system::error_code error;
size_t length = sock->read_some(boost::asio::buffer(data), 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.
boost::asio::write(*sock, boost::asio::buffer(data, length));
}
}
catch (std::exception& e)
{
std::cerr << "Exception in thread: " << e.what() << "\n";
}
}
What I want to do is save all the chunks or the read_some method into some buffer for this example std::string and then do something with them before sending a reply back:
const int max_length = 10;
typedef boost::shared_ptr<tcp::socket> socket_ptr;
void session(socket_ptr sock)
{
std::string dataReceived = "";
try
{
for (;;)
{
char data[max_length] = {'\0'};
boost::system::error_code error;
size_t length = sock->read_some(boost::asio::buffer(data), error);
dataReceived += std::string(data, length);
if (error == boost::asio::error::eof)
break; // Connection closed cleanly by peer.
else if (error)
throw boost::system::system_error(error); // Some other error.
//boost::asio::write(*sock, boost::asio::buffer(&dataReceived[0], dataReceived.size()));
}
boost::asio::write(*sock, boost::asio::buffer(&dataReceived[0], dataReceived.size()));
}
catch (std::exception& e)
{
std::cerr << "Exception in thread: " << e.what() << "\n";
}
}
When I remove the write from inside the loop the client hangs. The dataReceived has all the data inside. The buffer is deliberately small so that read_some is called more than once. In the debugger the control never goes to the write method outside of the loop. I am probably doing something very wrong. But I am unable to find out what.
Side question:
What would be the simplest solution to have a socket connection between some UI and a backend process?

Probably it hangs because client waits for server reply and don't send new data.
Also, server will exit form loop only when connection is closed, and there is nowhere to write data.

Related

Boost.Asio HTTP Server Session Closing

I have a http server based on Boost.Asio Example HTTP Server 2 (using an io_service-per-CPU design)
Each Request gets parsed, checked if it's a POST-Request, if Path is correct, if Content-Length Header is present, if one of these conditions is not correct, I generate a Bad-Request Response.
As everything is okay, I send a OK Response.
That's how it gets started.
int main(int argc, char* argv[])
{
try
{
http::server s("127.0.0.1", "88", 1024);
s.run();
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << "\n";
}
return 0;
}
Now I made a quick C# app which starts 16 Threads and each Thread sends continuously in a while(true)-Loop POST-Requests to this server.
A while it runs smoothly and fast. Then at some point of time the server gets unresponsive (Cannot connect to remote server).
A cause for this could be that the sessions from the server don't get closed properly.
Here's the code for Bad-Request/OK Responses:
void session::handle_request()
{
//Generate OK Response
reply_ = reply::stock_reply(reply::ok);
//Send OK Response
boost::asio::async_write(client_socket_, reply_.to_buffers(),
boost::bind(&session::handle_client_write, shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
void session::send_bad_request()
{
//Generate Bad Request Response
reply_ = reply::stock_reply(reply::bad_request);
//Send Bad Request Response
boost::asio::async_write(client_socket_, reply_.to_buffers(),
boost::bind(&session::handle_client_write, shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
And the handle_client_write which both trigger:
void session::handle_client_write(const boost::system::error_code& err, size_t len)
{
if (!err) {
//Dummy Error Code Var
boost::system::error_code ignored_ec;
//Shutdown socket
client_socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec);
client_socket_.close();
//std::cout << "Closed" << ignored_ec.message() << "\n";
}
else {
std::cout << "Error: " << err.message() << "\n";
}
}
Like I said, at some point it gets unresponsive and after little time it responses again.

TCP/IP client using Boost::asio

I'm trying to make a TCP/IP client using boost library. This is how I designed my program
->read thread to read from the server
->write thread to send commands
->a function that parses the read data from the server
int main()
{
TCP_IP_Connection router;
router.Create_Socket();
boost::thread_group t;
t.create_thread(boost::bind(&TCP_IP_Connection::get_status,&router,'i'));
t.create_thread(boost::bind(&TCP_IP_Connection::readTCP,&router));
std::string reply="\nend of main()";
std::cout<<reply;
t.join_all();
return 0;
}
void TCP_IP_Connection::Create_Socket()
{
tcp::resolver resolver(_io);//resolve into TCP endpoint
tcp::resolver::query query(routerip,rport);
tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
//list of endpoints
tcp::resolver::iterator end;
boost::asio::streambuf b;
_socket = new tcp::socket(_io); //create socket
boost::system::error_code error= boost::asio::error::host_not_found;
try
{
while (error && endpoint_iterator != end) //if error go to next endpoint
{
_socket->close();
_socket->connect(*endpoint_iterator++, error);
}
if(error)
throw boost::system::system_error(error);
//else the router is connected
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
}
}
void TCP_IP_Connection::get_status(char p)
{
try
{
if(p=='i')
_socket->send(boost::asio::buffer("llist\n\n"));
//sending command for input command
else
_socket->send(boost::asio::buffer(" sspo l1\n\n"));
//sending signal presence for output command
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
}
}
void TCP_IP_Connection::readTCP()
{
this->len=0;
boost::system::error_code error= boost::asio::error::host_not_found;
try
{ //loop reading all values from router
while(1)
{
//wait for reply??
_socket->async_read_some(boost::asio::buffer(this-
>reply,sizeof(this>reply)),boost::bind(&TCP_IP_Connection::dataProcess,this,
boost::asio::placeholders::error,boost::asio::placeholders::bytes_transferred));
_io.run();
if(error==boost::asio::error::eof) //connection closed by router
std::cout<<"connection closed by router";
}
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
}
}
void TCP_IP_Connection::dataProcess(const boost::system::error_code &er,size_t l)
{
if(!er)
{
if(l>0)
{
for(int i=0;i<l;i++)
{
this->data[i]=this->reply[i];
//if(data[i]="\n")
std::cout<<this->data[i];
}
}
}
}
When I run the code all I get is the response from the server that says the client is connected and not the response of the command I send. But when I try debugging I get full output as I need. Am I doing anything wrong in the threading, or in the TCP read buffer.
Your code is creating 2 threads. The first thread created has a thread function called get_status. In get_status, there is no looping so it only executes the code once. It appears to be sending the string "llist\n\n" to the server and this is done synchronously. After that, it does not send anything else. So, are you expecting the server to send other data after the first command is sent? The code in the first thread may or may not execute completely before the code in the second thread executes.
The second thread is created and this thread appears to be responsible for processing information coming off of the socket. There is an infinite loop of while(1), but no logic to exit the loop so it will run forever unless an exception is thrown. I believe that the async_read_some method will not cause any data to be transferred until the buffer is full. The size of the buffer is specified by the size of reply. This may be your problem since the dataProcess method won't get called until all of the data specified by the length of reply has been received. In many protocols, the first 4 bytes specifies the length of the message. So, if you are dealing with variable length messages, then your code will have to take this into account.
One other item worth mentioning is that the looping code in readTCP to call _io.Run is not really necessary. You can add a work object to your io_service object in order for it to run continuously. For example:
void SSLSocket::InitAsynchIO()
{
// This method is responsible for initiating asynch i/o.
boost::system::error_code Err;
string s;
stringstream ss;
//
try
{
ss << "SSLSocket::InitAsynchIO: Worker thread - " << Logger::NumberToString(boost::this_thread::get_id()) << " started.\n";
Log.LogString(ss.str(), LogInfo);
// Enable the handlers for asynch i/o. The thread will hang here until the stop method has been called or an error occurs.
// Add a work object so the thread will be dedicated to handling asynch i/o.
boost::asio::io_service::work work(*IOService);
IOService->run();
Log.LogString("SSLSocket::InitAsynchIO: receive worker thread done.\n", LogInfo);
}
catch (std::exception& e)
{
stringstream ss;
ss << "SSLSocket::InitAsynchIO: threw an error - " << e.what() << ".\n";
Log.LogString(ss.str(), LogError);
Stop();
}
}
It is ok to have your first thread do your first async read. Your read handler can be set up to call itself in order to handle the next message. For example:
void SSLSocket::HandleRead(const boost::system::error_code& error, size_t bytesTransferred)
{
// This method is called to process an incomming message.
//
std::stringstream ss;
int ByteCount;
try
{
ss << "SSLSocket::HandleRead: From worker thread " << boost::this_thread::get_id() << ".\n";
Log.LogString(ss.str(), LogInfo);
// Set to exit this thread if the user is done.
if (!ReqAlive)
{
// IOService->stop();
return;
}
if (!error)
{
// Get the number of bytes in the message.
if (bytesTransferred == 4)
{
ByteCount = BytesToInt(pDataBuf);
}
else
{
// Call the C# callback method that will handle the message.
ss << "SSLSocket::HandleRead: From worker thread " << boost::this_thread::get_id() << "; # bytes transferred = " << bytesTransferred << ".\n";
Log.LogString(ss.str(), LogDebug2);
Log.LogBuf(pDataBuf, (int)bytesTransferred, true, LogDebug3);
Log.LogString("SSLSocket::HandleRead: sending msg to the C# client.\n\n", LogDebug2);
CallbackFunction(this, bytesTransferred, (void*)pDataBuf);
// Prepare to read in the next message length.
ByteCount = MsgLenBytes;
}
pDataBuf = BufMang.GetPtr(ByteCount);
boost::system::error_code Err;
// boost::asio::async_read(pSocket, boost::asio::buffer(pDataBuf, ByteCount), boost::bind(&SSLSocket::HandleRead,
// this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
Locking CodeLock(SocketLock); // Single thread the code.
boost::asio::async_read(*pSocket, boost::asio::buffer(pDataBuf, ByteCount), boost::bind(&SSLSocket::HandleRead,
this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
// boost::asio::read(pSocket, boost::asio::buffer(reply_), boost::asio::transfer_exactly(ByteCount), Err);
}
else
{
Log.LogString("SSLSocket::HandleRead failed: " + error.message() + "\n", LogError);
Stop();
}
}
catch (std::exception& e)
{
stringstream ss;
ss << "SSLSocket::HandleRead: threw an error - " << e.what() << ".\n";
Log.LogString(ss.str(), LogError);
Stop();
}
}
If none of the above is helpful, then put in some debug code that logs all of the calls to a log file so that you can see what is going on. You might also want to consider downloading Wire Shark in order to see what data is going out and coming in.

boost tcp socket with shared_ptr c++

I am trying to wrap the boost TCP using a new class in c++. Things work like a charm while I call the boost function directly. However I fail to call socket close while the close is wrap in a class function. Please help have a look on the following codes.
class defination:
typedef boost::shared_ptr<tcp::socket> Socket;
class TCPConnector{
public :
bool isConnected;
Socket sock;
string ip;
int port;
TCPConnector(string ip, int port);
void Close();
bool Connect();
};
functions:
TCPConnector::TCPConnector(string ip,int port):ip(ip),port(port)
{
}
void TCPConnector::Close() {
boost::system::error_code error;
if (!isConnected)
return;
isConnected = false;
try {
sock->shutdown(boost::asio::ip::tcp::socket::shutdown_both, error);
cout << "ShutDown" << endl;
if (error)
throw boost::system::system_error(error);
sock->close(error);
if (error)
throw boost::system::system_error(error);
} catch (exception& e) {
cout << "#TCPConnector::Close()#" << e.what() << endl;
}
}
Main Function:
int main(int argc, char* argv[]) {
try {
TCPConnector* conn = new TCPConnector("127.0.0.1",8088);
for (int i = 0; i < 2; i++) {
boost::asio::io_service io_service;
tcp::resolver resolver(io_service);
tcp::resolver::query query(tcp::v4(), "127.0.0.1", "8088");
tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
conn->sock.reset(new tcp::socket(io_service));
conn->sock->connect(*endpoint_iterator);
cout << "Connected" << endl;
boost::thread acceptorThread(boost::bind(receive,conn));
sleep(1);
unsigned char msg[8] = { 0, 6, 55, 56, 55, 56, 55, 0 };
boost::system::error_code error;
try {
boost::asio::write(*conn->sock, boost::asio::buffer(msg, 8),
boost::asio::transfer_all(), error);
cout << "Sent" << endl;
if (error)
throw boost::system::system_error(error);
conn->sock->shutdown(boost::asio::ip::tcp::socket::shutdown_both,
error);
if (error)
throw boost::system::system_error(error);
conn->sock->close(error);//close socket directly , the result is ok
//conn->Close();// close by calling functions, it causes problems.
cout << "Closed" << endl;
if (error)
throw boost::system::system_error(error);
io_service.stop();
} catch (std::exception& e) {
std::cerr << "Exception in thread: " << e.what() << "\n";
}
cout << "Sleep" << endl;
sleep(2);
cout << "Wake up" << endl;
}
} catch (std::exception& e) {
std::cerr << e.what() << std::endl;
}
return 0;
}
These 2 lines give the different behaviours. I don't know why the second one will cause problem.
conn->sock->close(error);//close socket directly , the result is ok
conn->Close();// close by calling functions, it causes problems.
mutex: Invalid argument was printed on
sock->close(error);
if (error)
throw boost::system::system_error(error);
Is the problem related to shared_ptr? or I missed something important to close the socket?
Thanks for any suggestion.
The problem is that the io_service should outlive the socket.
On all but the first iteration of the for loop, the statement conn->sock.reset(new tcp::socket(io_service)); calls the destructor of the previous iteration's socket. This destructor accesses elements of the previous iteration's io_service (specifically its mutex) which by that point have themselves been destroyed.
To fix this, you can move the io_service outside the for loop, or you can call conn->sock.reset(); at the end of the for loop in order to invoke the socket's destructor while the io_service is still valid.

Boost async_read

I'm trying to create a TCP server where the Start() method blocks until a connection is accepted, and then begins a series of asynchronous reads. I have the following code, and when I connect using telnet I get this output:
Waiting for a new connection
Connection accepted
terminate called throwing an exceptionAbort trap: 6
Here is the code:
void SocketReadThread::Start()
{
bzero(m_headerBuffer, HEADER_LEN);
m_running = true;
asio::io_service ios;
asio::ip::tcp::acceptor acp (ios,
boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), GUI_PORT));
asio::ip::tcp::socket sock(ios);
std::cout << "Waiting for a new connection" << std::endl;
acp.accept(sock);
std::cout << "Connection accepted" << std::endl;
asio::async_read(sock, asio::buffer(m_headerBuffer, HEADER_LEN),
boost::bind(&SocketReadThread::handleReadHeader, shared_from_this(),
asio::placeholders::error));
ios.run();
}
void SocketReadThread::handleReadHeader(const system::error_code& error)
{
std::cout << "Read two bytes!" << std::endl;
}
You should wrap your main() function in try {...} catch (std::exception& e) { cout << e.what(); } block.
You're probably doing something scary (and awesome) to the stack by declaring your ReadHandler incorrectly. Even if you ignore some parameters, the signature must be:
void handler (
const boost::system::error_code& error, // Result of operation.
std::size_t bytes_transferred // Number of bytes copied into the
// buffers. If an error occurred,
// this will be the number of
// bytes successfully transferred
// prior to the error.
);

How to Optimize Client/Server with C/C++ and Boost Asio

I have two applications which work like a TCP client/server.
First application is the client which uses OpenCV to detect and send commands via TCP to the Server which controls a mobile robot.
My applications work well if I'm in my developing computer, but when I test it in real world with my robot, i realize that I have some delays with the data exchanged between client and server.
This happens because the computer where iItest the applications is a little bit slow compared to my developing computer which is faster and give no problems. In real world case, server doesn't receive packets from client in real time so it execute the operations with a delay.
So, the problem is when the client loose the detection and send commands to the server in order to stop it. The server receives packets with a delay so when clients sends stop (heading = 0, distance = 0, nodetection) server doesn't receive the command immediately because it is receiving previous command packets and so it stop only after few meters.
I'd like to find a solution in order to stop immediately the server and discard all the packages about the moving information because they are useless if the robot has to stop.
In order to stop the robot I send a nodetecting package which unfortunately is not received in real time so the robot continue to move for a while.
(I'm doing this test on the same machine, so I connect on localhost)
At the moment, client uses this code:
while (key_mode!='q')
{
//wait and error processing
context.WaitAnyUpdateAll();
// obtain al the metadata image,depthmap and scene
Mat frame = getImageFromKinect();
// do detection and tracking
switch(mode)
{
..
case ROBOT_CONTROL:
{
// Connect to the server
using boost::asio::ip::tcp;
boost::asio::io_service io_service;
tcp::resolver resolver(io_service);
tcp::resolver::query query(tcp::v4(), server, boost::lexical_cast<string>(porta));
tcp::resolver::iterator iterator = resolver.resolve(query);
tcp::socket s(io_service);
try
{
s.connect(*iterator);
}
catch (boost::system::system_error const& e)
{
std::cout << "Warning: could not connect to the server\n" << e.what() << "\nPossible Solution: try to check is Server is UP\n" << std::endl;
}
..
..
float delta = heading - last_heading;
if (!is_equal(delta, 0.0)){
// heading_data = send_heading + token + boost::lexical_cast<std::string>(delta);
// heading_length = strlen(heading_data.c_str());
try
{
// boost::asio::write(s, boost::asio::buffer(heading_data, heading_length));
}
catch (boost::system::system_error const& e)
{
std::cout << "Warning: could not send commands : " << e.what() << std::endl;
}
}
last_heading = heading; // store current for next subtraction
#endif
#if 1
heading_scalato = heading / 3.0;
heading_data = send_heading + token + boost::lexical_cast<std::string>(heading_scalato);
heading_length = strlen(heading_data.c_str());
try
{
boost::asio::write(s, boost::asio::buffer(heading_data, heading_length));
}
catch (boost::system::system_error const& e)
{
std::cout << "Warning: could not send commands : " << e.what() << std::endl;
}
#endif
distance_data = send_distance + token + boost::lexical_cast<std::string>(distance);
distance_length = strlen(distance_data.c_str());
try
{
boost::asio::write(s, boost::asio::buffer(distance_data, distance_length));
}
catch (boost::system::system_error const& e)
{
std::cout << "Warning: could not connect : " << e.what() << std::endl;
}
..
..
// if it has to stop:
else
{
// stop rover
//control.setHeading(0.0);
//control.setDistance(0.0);
float heading = 0.0;
float distance = 0.0;
heading_data = send_heading + token + boost::lexical_cast<std::string>(heading);
distance_data = send_distance + token + boost::lexical_cast<std::string>(distance);
heading_length = heading_data.size();//strlen(heading_data.c_str());
distance_length = strlen(distance_data.c_str());
try
{
boost::asio::write(s, boost::asio::buffer(heading_data, heading_length));
boost::asio::write(s, boost::asio::buffer(distance_data, distance_length));
}
catch (boost::system::system_error const& e)
{
std::cout << "Warning: could not send commands : " << e.what() << std::endl;
}
// write info on image
char text[100];
sprintf(text,"ROBOT CONTROL: No detection");
putText(hogResultFrame,text,Point(4,89),FONT_HERSHEY_PLAIN,1,Scalar(0,0,0));
putText(hogResultFrame,text,Point(5,90),FONT_HERSHEY_PLAIN,1,Scalar(100,100,255));
nodetection_length = nodetection.size();
try
{
boost::asio::write(s, boost::asio::buffer(nodetection, nodetection_length));
}
catch (boost::system::system_error const& e)
{
std::cout << "Warning: could not send commands : " << e.what() << std::endl;
}
In server, i use:
void* runThread(void*)
{
while(Aria::getRunning())
{
if(start_routine){
if(temp_heading < 0.0){
printf("\n\nStarting Discovering routine, then sleeping 3 seconds.\a\n\n");
robot.setRotVel(5.0);
ArUtil::sleep(3000);
temp_heading = -1;
}
else if(temp_heading >= 0.0) {
printf("\n\nStarting Clockwise Discovering routine, then sleeping 3 seconds.\a\n\n");
robot.setRotVel(-5.0);
ArUtil::sleep(3000);
temp_heading = 1;
}
}
if( !flag_heading && !flag_distance)
{
myMutex.lock();
temp_heading=m_heading;
temp_distance=m_distance;
myMutex.unlock();
if (is_equal(temp_heading, 0.0)){
robot.setRotVel(0.0);
}
else robot.setRotVel(-ArMath::radToDeg(temp_heading));
if(temp_distance <= distanza_minima || is_equal(temp_distance, 0.0))
robot.setVel(0.0);
else
robot.setVel(float(temp_distance/20));
printf("runThread:: heading= %f distance = %f rob_vel = %f rob_rot_vel = %f\n",ArMath::radToDeg(temp_heading),temp_distance, robot.getVel(),robot.getRotVel());
flag_heading = true;
flag_distance = true;
start_routine = false;
}
ArUtil::sleep(100);
}
}
DataLine GetValueFromLine(const std::string& sData) {
std::string sName, sInteger;
std::stringstream ss;
DataLine Result;
size_t sz = sData.find('#');
sName = sData.substr(0,sz); // Just in case you need it later
Result.sName = sName;
sInteger = sData.substr(sz + 1,sData.length() - sz);
ss.str(sInteger);
ss >> Result.nNumber;
if (ss.fail()) {
// something went wrong, probably not an integer
}
return Result;
}
void session(socket_ptr sock)
{
try
{
for (;;)
{
char data[max_length];
boost::system::error_code error;
size_t length = sock->read_some(boost::asio::buffer(data), error);
data[length] = 0;
if (error == boost::asio::error::eof)
break; // Connection closed cleanly by peer.
else if (error)
throw boost::system::system_error(error); // Some other error.
output = GetValueFromLine(data);
std::cout << "*******************\n";
comando = output.sName;
valore = output.nNumber;
if (output.sName == "nodetection"){
start_routine = true;
std::cout << "\nSto ricevendo: " << output.sName;
}
else if (output.sName == "heading"){
start_routine = false;
control.setHeading(output.nNumber);
std::cout << "\nSto ricevendo: " << output.sName << "e heading: " << output.nNumber;
}
else if (output.sName == "distance"){
start_routine = false;
control.setDistance(output.nNumber);
std::cout << "\nSto ricevendo: " << output.sName << "e distance: " << output.nNumber;
}
// boost::asio::write(*sock, boost::asio::buffer(data, length));
}
}
catch (std::exception& e)
{
std::cerr << "Exception in thread: " << e.what() << "\n";
}
}
void server(boost::asio::io_service& io_service, short port)
{
tcp::acceptor a(io_service, tcp::endpoint(tcp::v4(), port));
for (;;)
{
socket_ptr sock(new tcp::socket(io_service));
a.accept(*sock);
boost::thread t(boost::bind(session, sock));
}
}
int main(int argc, char **argv)
{
// control server initialitation..
....
boost::asio::io_service io_service;
server(io_service, porta);
return 0;
}
I was thinking to force the client to close the TCP connection when it reaches a no detecting condition in order to force the server to reject the pending packets, but how I can do this?
How to destroy s pointer in boost?
Are there any other solutions?
If I close the connection, does the server reject the pending packets?
As I understand your problem, you have a message that you intend your application to abandon all current processing and flush the input queue. However, because the application is busy receiving and processing previous messages, it does not receive the abandon and flush message until all previous messages are processed - which makes abandon and flush a no operation
IMHO you need to design and code a multithreaded application.
One thread, as light weight as possible, reads the incoming messages as fast as possible and quickly checks for the abandon and flush message. If the message is OK, then it is added to a queue and the next message is checked.
The second thread pulls the messages from the queue where the messages are stored by the first thread and processes them, perhaps taking a long time to do so. From time time it checks for an abandon and flush signal from the first thread.
Another approach to consider: the application that sends the messages maintains the queue. When the application which receives the messages finishes processing a message, it sends a request for the next message. The sender only sends messages when requested. If the abandon and flush condition arises, the application sending the messages looks after this. The application receiving the messages only has to deal with one at a time. This approach greatly simplify the message receiver, at the cost of complexity in the sending application, a more elaborate communications protocol and, possibly, a reduction in maximum throughput.