TcpClient, not yet multithreaded

master
Denes Matetelki 13 years ago
parent 45b40ae03b
commit 870739f8a8

@ -13,6 +13,9 @@
#include <stdexcept> // runtime_error
#include <sstream> // ostringstream
#include <errno.h> // errno
#include <string.h> // strerror
const long NANO = 1000000000L; // 10^9
@ -112,4 +115,10 @@ inline void StrToT( T &t, const std::string s )
ss >> t;
}
inline std::string errnoToString(const char *s)
{
return std::string(s).append(strerror(errno));
}
#endif // COMMON_HPP

@ -0,0 +1,45 @@
#ifndef TCP_CLIENT_HPP
#define TCP_CLIENT_HPP
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
class TcpClient
{
public:
TcpClient ( const std::string host,
const std::string port );
~TcpClient();
bool connect();
bool disconnect();
bool send(const std::string msg);
bool receive(std::string &reply);
private:
bool openSocket();
bool closeSocket();
bool connectToHost();
bool getHostInfo(struct addrinfo **servinfo);
void printHostDetails(struct addrinfo *servinfo);
bool connectToFirstAddress(struct addrinfo *servinfo);
int m_socket;
std::string m_host;
std::string m_port;
bool m_connected;
};
#endif // TCP_CLIENT_HPP

Binary file not shown.

@ -0,0 +1,75 @@
#include "socketClient.hpp"
#include <errno.h> // errno
#include <string.h> // strerror
#include <iostream>
SocketClient::SocketClient( const int addrDomain,
const int socketType )
: m_connected(false)
, m_addrDomain(addrDomain)
, m_socketType(socketType)
, m_socketfd(0)
{
}
SocketClient::~SocketClient()
{
if ( m_connected && close(m_socketfd) == -1 )
std::cerr << errorToString("ERROR closing socket. ") << std::endl;
}
bool SocketClient::send(const std::string msg)
{
if ( !m_connected && !this->connect() )
return false;
ssize_t n = write(m_socketfd, msg.c_str(), msg.length());
if (n == -1) {
std::cerr << errorToString("ERROR writing to socket. ") << std::endl;
return false;
} else if ( n < (ssize_t)msg.length() ) {
std::cerr << "Only a part of msg has been written to socket. " << std::endl;
return false;
}
return true;
}
bool SocketClient::receive(std::string &reply)
{
if ( !m_connected && !this->connect() )
return false;
char buffer[256];
ssize_t n = read(m_socketfd, buffer, 255);
if (n == -1) {
std::cerr << errorToString("ERROR reading from socket. ") << std::endl;
return false;
}
reply = std::string(buffer, n);
return true;
}
bool SocketClient::connect(void)
{
m_socketfd = socket(m_addrDomain, m_socketType, 0);
if ( m_socketfd == -1 ) {
std::cerr << errorToString("ERROR opening socket. ") << std::endl;
return false;
}
return connectToPeer();
}
std::string SocketClient::errnoToString(const char *s) const
{
return std::string(s).append(strerror(errno));
}

@ -24,7 +24,7 @@ protected:
bool connect(void);
virtual bool connectToPeer(void) = 0;
std::string errorToString(const char *s) const;
std::string errnoToString(const char *s) const;
bool m_connected;
int m_addrDomain;

@ -0,0 +1,32 @@
// gpp tcpclient_main.cpp -o client -I../include ../src/Logger.cpp ../src/TcpClient.cpp
#include "TcpClient.hpp"
#include "Logger.hpp"
#include <iostream>
#include <string>
int main( int argc, char * argv[] )
{
Logger::createInstance();
Logger::init(std::cout);
Logger::setLogLevel(Logger::FINEST);
TcpClient tcpclient("localhost", "4455");
tcpclient.connect();
tcpclient.send("madao");
std::string reply;
tcpclient.receive(reply);
std::cout << "got reply \"" << reply << "\"" << std::endl;
tcpclient.disconnect();
Logger::destroy();
return 0;
}

@ -0,0 +1,226 @@
#include "TcpClient.hpp"
#include "Logger.hpp"
#include "Common.hpp"
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h> // inet_ntop
TcpClient::TcpClient( const std::string host,
const std::string port )
: m_socket(-1)
, m_host(host)
, m_port(port)
, m_connected(false)
{
TRACE;
}
TcpClient::~TcpClient()
{
TRACE;
disconnect();
}
bool TcpClient::connect()
{
TRACE;
if ( !openSocket() )
return false;
if ( !connectToHost() )
return false;
m_connected = true;
return true;
}
bool TcpClient::disconnect()
{
TRACE;
if ( !closeSocket() )
return false;
return true;
}
bool TcpClient::send(const std::string msg)
{
TRACE;
ssize_t n = write(m_socket, msg.c_str(), msg.length());
if (n == -1) {
LOG( Logger::ERR, errnoToString("ERROR writing to socket. ").c_str() );
return false;
}
return true;
}
bool TcpClient::receive(std::string &reply)
{
TRACE;
char buffer[256];
ssize_t n = read(m_socket, buffer, 255);
if (n == -1) {
LOG( Logger::ERR, errnoToString("ERROR reading from socket. ").c_str() );
return false;
}
reply = std::string(buffer, n);
return true;
}
bool TcpClient::openSocket()
{
TRACE;
m_socket = socket(AF_INET, SOCK_STREAM, 0);
if ( m_socket == -1 ) {
LOG( Logger::ERR, errnoToString("ERROR opening socket. ").c_str() );
return false;
}
return true;
}
bool TcpClient::closeSocket()
{
TRACE;
/// @note are the return values of shutdown and close meaningful?
// if ( shutdown(m_socket, SHUT_RDWR) == -1 ) {
// LOG( Logger::ERR, errnoToString("ERROR shuting down socket. ").c_str() );
// return false;
// }
//
// if ( close(m_socket) == -1 ) {
// LOG( Logger::ERR, errnoToString("ERROR closing socket. ").c_str() );
// return false;
// }
shutdown(m_socket, SHUT_RDWR);
close(m_socket);
m_socket = -1;
return true;
}
bool TcpClient::connectToHost()
{
TRACE;
struct addrinfo *results(0);
if ( !getHostInfo(&results) )
return false;
printHostDetails(results);
if ( !connectToFirstAddress(results) )
return false;
freeaddrinfo(results);
return true;
}
bool TcpClient::getHostInfo(struct addrinfo **servinfo)
{
TRACE;
struct addrinfo hints;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC; // Allow IPv4 or IPv6
hints.ai_socktype = SOCK_DGRAM; // Datagram socket
hints.ai_flags = AI_PASSIVE; // For wildcard IP address
hints.ai_protocol = 0; // Any protocol
hints.ai_canonname = NULL;
hints.ai_addr = NULL;
hints.ai_next = NULL;
struct addrinfo *results;
int status = getaddrinfo(m_host.c_str(), m_port.c_str(), &hints, &results);
if (status != 0) {
LOG( Logger::ERR, std::string("Error at network address translation: ").
append(gai_strerror(status)).c_str() ) ;
return false;
}
*servinfo = results;
return true;
}
void TcpClient::printHostDetails(struct addrinfo *servinfo)
{
TRACE;
int counter(0);
for ( struct addrinfo *it = servinfo; it != 0; it = it->ai_next) {
counter++;
void *addr;
std::string ipver;
if ( it->ai_family == AF_INET) { // IPv4
struct sockaddr_in *ipv4 = (struct sockaddr_in *)it->ai_addr;
addr = &(ipv4->sin_addr);
ipver = "IPv4";
} else { // IPv6
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)it->ai_addr;
addr = &(ipv6->sin6_addr);
ipver = "IPv6";
}
char ipstr[INET6_ADDRSTRLEN];
inet_ntop( it->ai_family, addr, ipstr, sizeof ipstr );
LOG( Logger::DEBUG, std::string(TToStr(counter)).append(". address is ").
append(ipver).append(": ").
append(ipstr).c_str() );
}
}
bool TcpClient::connectToFirstAddress(struct addrinfo *servinfo)
{
TRACE;
for ( struct addrinfo *it = servinfo; it != 0; it = it->ai_next)
if (::connect(m_socket, it->ai_addr, it->ai_addrlen) != -1) {
char hostBuffer[256];
char serviceBuffer[256];
int status = getnameinfo( it->ai_addr, it->ai_addrlen,
hostBuffer, sizeof(hostBuffer),
serviceBuffer, sizeof(serviceBuffer),
NI_NAMEREQD );
if ( status != 0 ) {
LOG( Logger::WARNING, std::string("Could not resolve hostname. ").
append(gai_strerror(status)).c_str() );
} else {
LOG( Logger::DEBUG, std::string("Connected to ").
append(hostBuffer).append(":").
append(serviceBuffer).c_str() );
}
return true;
}
LOG( Logger::ERR, std::string("Could not connect to host,"
" connection refused.").c_str() );
return false;
}

@ -69,7 +69,7 @@ bool SocketClient::connect(void)
return connectToPeer();
}
std::string SocketClient::errorToString(const char *s) const
std::string SocketClient::errnoToString(const char *s)
{
return std::string(s).append(strerror(errno));
}

@ -8,6 +8,7 @@
#include "ArgParse.hpp"
#include <string>
#include <stdexcept>
class TestArgParseSuite : public CxxTest::TestSuite
{
@ -46,7 +47,7 @@ public:
TS_ASSERT_EQUALS( argParse.findKeyinArgMap("-r"), argParse.m_params.end() );
}
void asdtestAddArgs( void )
void testAddArgs( void )
{
TEST_HEADER;
@ -70,4 +71,59 @@ public:
TS_ASSERT_EQUALS( argParse.foundArg("-u, --user"), true );
}
void testBadAddArgs( void )
{
TEST_HEADER;
ArgParse argParse("intro", "outro");
TS_ASSERT_THROWS( argParse.addArgument("s", "no dash"),
std::logic_error);
TS_ASSERT_THROWS( argParse.addArgument("-i", "bad range", ArgParse::INT,
ArgParse::OPTIONAL, ArgParse::OPTIONAL, "", "12..forever"),
std::logic_error);
TS_ASSERT_THROWS( argParse.addArgument("-i", "bad range", ArgParse::FLOAT,
ArgParse::OPTIONAL, ArgParse::OPTIONAL, "", "12.34..forever"),
std::logic_error);
}
void testgetArgs( void )
{
TEST_HEADER;
ArgParse argParse("intro", "outro");
argParse.addArgument("-i", "int", ArgParse::INT);
argParse.addArgument("-f", "float", ArgParse::FLOAT);
argParse.addArgument("-n", "none", ArgParse::NONE);
argParse.addArgument("-s", "string", ArgParse::STRING);
argParse.addArgument("-b", "bool", ArgParse::BOOL);
int argc = 10;
char *argv[] = { (char*)"test",
(char*)"-i", (char*)"12",
(char*)"-f", (char*)"12.12",
(char*)"-n",
(char*)"-s", (char*)"forever",
(char*)"-b", (char*)"false" };
argParse.parseArgs(argc, argv);
int i;
float f;
std::string s;
bool b;
TS_ASSERT_EQUALS( argParse.argAsInt("-i", i), true );
TS_ASSERT_EQUALS( argParse.argAsFloat("-f", f), true );
TS_ASSERT_EQUALS( argParse.argAsString("-s", s), true );
TS_ASSERT_EQUALS( argParse.argAsBool("-b", b), true );
TS_ASSERT_EQUALS(i, 12 );
TS_ASSERT_DELTA(f, 12.12, 0.01 );
TS_ASSERT_EQUALS(s, std::string("forever") );
TS_ASSERT_EQUALS(b, false );
}
};

Loading…
Cancel
Save