poco/FSM/samples/TCP/AppClient.cpp
2016-07-18 14:34:53 +02:00

378 lines
9.6 KiB
C++

//
// The contents of this file are subject to the Mozilla Public
// License Version 1.1 (the "License"); you may not use this file
// except in compliance with the License. You may obtain a copy
// of the License at http://www.mozilla.org/MPL/
//
// Software distributed under the License is distributed on an
// "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
// implied. See the License for the specific language governing
// rights and limitations under the License.
//
// The Original Code is State Machine Compiler (SMC).
//
// The Initial Developer of the Original Code is Charles W. Rapp.
// Portions created by Charles W. Rapp are
// Copyright (C) 2000 - 2007. Charles W. Rapp.
// All Rights Reserved.
//
// Contributor(s):
//
// Name
// AppClient.cpp
//
// Description
// TcpClient listener object.
//
// RCS ID
// $Id: AppClient.cpp,v 1.6 2007/12/28 12:34:40 cwrapp Exp $
//
// CHANGE LOG
// $Log: AppClient.cpp,v $
// Revision 1.6 2007/12/28 12:34:40 cwrapp
// Version 5.0.1 check-in.
//
// Revision 1.5 2005/05/28 13:31:18 cwrapp
// Updated C++ examples.
//
// Revision 1.0 2003/12/14 19:34:34 charlesr
// Initial revision
//
#include "AppClient.h"
#include "AppServer.h"
#include "Eventloop.h"
#if defined(WIN32)
#include <winsock2.h>
#include <iostream>
#include <time.h>
#else
#include <arpa/inet.h>
#endif
#include <stdlib.h>
#include <memory.h>
using namespace std;
// Externally defined global variables.
extern Eventloop *Gevent_loop;
// Class variables.
int AppClient::_initFlag = 0;
const long AppClient::MIN_SLEEP_TIME = 100;
const long AppClient::MAX_SLEEP_TIME = 30000;
//---------------------------------------------------------------
// AppClient() (Public)
// Default constructor.
//
AppClient::AppClient()
: _client_socket(NULL),
_owner(NULL),
_host(),
_messageCount(0)
{}
//---------------------------------------------------------------
// AppClient(const char*, TcpClient&, AppServer&) (Public)
// An "accept" construct.
//
AppClient::AppClient(const string& host,
TcpClient& tcp_client,
AppServer& owner)
: _client_socket(&tcp_client),
_owner(&owner),
_host(host),
_messageCount(0)
{
// Tell the client that this object is now listening to it.
tcp_client.setListener(*this);
// Since this client is already connected, set the
// random transmit timer.
setTransmitTimer();
return;
} // end of AppClient::AppClient(TcpClient&, AppServer&)
//---------------------------------------------------------------
// ~AppClient() (Public)
// Destructor.
//
AppClient::~AppClient()
{
if (_client_socket != NULL)
{
delete _client_socket;
_client_socket = NULL;
}
return;
} // end of AppClient::~AppClient()
//---------------------------------------------------------------
// getHost() const (Public)
// Return the host name.
//
const string& AppClient::getHost() const
{
return(_host);
} // end of AppClient::getHost() const
//---------------------------------------------------------------
// open(const string&, const sockaddr_in&) (Public)
// Open a connection to the named TCP service.
//
void AppClient::open(const string& host,
const sockaddr_in& address)
{
if (_client_socket == NULL)
{
// Store away the host name.
_host = host;
cout << "Opening connection to "
<< host
<< ":"
<< ntohs(address.sin_port)
<< " ... ";
// Create the client object and open it.
_client_socket = new TcpClient(*this);
_client_socket->open(address);
}
return;
} // end of AppClient::open(const string&, const sockaddr_in&)
//---------------------------------------------------------------
// close() (Public)
// Close the client connection.
//
void AppClient::close()
{
if (_client_socket != NULL)
{
cout << "Closing connection to "
<< _host
<< ":"
<< ntohs((_client_socket->getServerAddress()).sin_port)
<< " ... ";
_client_socket->doClose();
}
return;
} // end of AppClient::close()
//---------------------------------------------------------------
// opened(TcpConnection&) (Public)
// TCP client connection successful.
//
void AppClient::opened(TcpConnection&)
{
cout << "open successful." << endl;
// Set the transmit timer.
setTransmitTimer();
return;
} // end of AppClient::opened(TcpConnection&)
//---------------------------------------------------------------
// openFailed(const char*, TcpConnection&) (Public)
// TCP client connection failed.
//
void AppClient::openFailed(const char *reason, TcpConnection&)
{
void socketClosed();
cout << "open failed";
if (reason == NULL)
{
cout << "." << endl;
}
else
{
cout << " - "
<< reason
<< endl;
}
// Let the application know that the socket is closed.
socketClosed();
return;
} // end of AppClient::openFailed(const char*, TcpConnection&)
//---------------------------------------------------------------
// transmitted(TcpConnection&) (Public)
// Data successfully transmitted.
//
void AppClient::transmitted(TcpConnection&)
{
// Set the timer for the next transmission.
setTransmitTimer();
cout << "transmit successful." << endl;
return;
} // end of AppClient::transmitted(TcpConnection&)
//---------------------------------------------------------------
// transmitFailed(const char*, TcpConnection&) (Public)
// Failed to send data to far-end.
//
void AppClient::transmitFailed(const char *reason, TcpConnection&)
{
cout << "transmit failed - " << reason << "." << endl;
return;
} // end of AppClient::transmitFailed(const char*, TcpConnection&)
//---------------------------------------------------------------
// receive(const char*, int, TcpConnection&) (Public)
// Received data from far end.
//
void AppClient::receive(const char *data,
int size,
TcpConnection&)
{
const sockaddr_in& address = _client_socket->getServerAddress();
char *string = new char[size + 1];
// Turn the data into a string.
(void) memcpy(string, data, size);
string[size] = '\0';
cout << "Received data from "
<< inet_ntoa(address.sin_addr)
<< ":"
<< ntohs(address.sin_port)
<< ": \""
<< string
<< "\""
<< endl;
delete[] string;
return;
} // end of AppClient::receive(const char*, int, TcpConnection&)
//---------------------------------------------------------------
// halfClosed(TcpConnection&) (Public)
// This far end has closed its connection. Close down this side.
//
void AppClient::halfClosed(TcpConnection&)
{
const sockaddr_in& address = _client_socket->getServerAddress();
cout << "Connection from "
<< _host
<< ":"
<< address.sin_port
<< " has closed its side."
<< endl
<< "Closing connection to "
<< _host
<< ":"
<< ntohs(address.sin_port)
<< " ... ";
// Stop the transmit timer if running.
Gevent_loop->stopTimer("TRANSMIT_TIMER", *this);
// When this timer expires, close this end of the connection,
// after waiting one millisecond.
Gevent_loop->startTimer("CLOSE_TIMER", 1, *this);
return;
} // end of AppClient::halfClosed(TcpConnection&)
//---------------------------------------------------------------
// closed(const char*, TcpConnection&) (Public)
// This client connection is closed.
//
void AppClient::closed(const char*, TcpConnection&)
{
void socketClosed();
cout << "closed." << endl;
// Stop the transmit timer if running.
Gevent_loop->stopTimer("TRANSMIT_TIMER", *this);
// If this is an accepted connection, tell the service owner
// that this connection is gone.
if (_owner != NULL)
{
_owner->clientClosed(*this);
}
else
{
// Tell the client application that this connection is
// closed.
socketClosed();
}
return;
} // end of AppClient::closed(const char*, TcpConnection&)
//---------------------------------------------------------------
// handleTimeout(const char*) (Public)
// Time to send another message.
//
void AppClient::handleTimeout(const char *name)
{
if (strcmp(name, "TRANSMIT_TIMER") == 0)
{
char message[30];
const sockaddr_in& address = _client_socket->getServerAddress();
(void) sprintf(message,
"This is message #%d.",
++_messageCount);
cout << "Transmitting to "
<< _host
<< ":"
<< ntohs(address.sin_port)
<< ": \""
<< message
<< "\" ... ";
_client_socket->transmit(message, 0, strlen(message));
}
else if (strcmp(name, "CLOSE_TIMER") == 0)
{
_client_socket->doClose();
}
return;
} // end of AppClient::handleTimeout(const char*)
//---------------------------------------------------------------
// setTransmitTimer() (Private)
// Set the transmit timer to expire some random time in the
// future.
//
void AppClient::setTransmitTimer()
{
long duration;
// Initialize the random number generator, if necessary.
if (_initFlag == 0)
{
srand(time(NULL));
_initFlag = 1;
}
// Set the next tranmission to some random time.
duration = ((long) rand()) % MAX_SLEEP_TIME;
if (duration < MIN_SLEEP_TIME)
{
duration = MIN_SLEEP_TIME;
}
Gevent_loop->startTimer("TRANSMIT_TIMER", duration, *this);
return;
} // end of AppClient::setTransmitTimer()