Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Class that uses sockets as a private class variable 1

Status
Not open for further replies.

Kirsle

Programmer
Jan 21, 2006
1,179
US
I'm relatively new to C++ - I usually use Perl, then dabbled in some Java, and have been teaching myself C++ for the past week or so.

I'm trying to make a class that connects to a simple chat room that uses a simple but proprietary protocol, called CyanChat -
I figured I'll program this to take a step away from all the "tutorial programs" and build something practical, and learn more in the process. I've implemented a CyanChat client library in Perl and in Java (here's the Java version for reference:
The problem I'm running into is that the class needs a socket object of some sort as a class-level private variable, so it needs to be available across multiple class functions (namely, a connect() function, a send(), receive(), and disconnect()). I've tried a couple different socket classes with not much success.

I've tried: Rude Sockets, the GPL "C++ Sockets Library", and a "hand-rolled" sockets class I got from a different site.

Here is the code I have so far:

CCBot.cpp - An implementation of my class

Code:
#include <iostream>
#include "CyanChat.h"

int main()
{
   using namespace std;
   cout << "CyanChat Bot Initializing" << endl;

   // Initialize a CC object
   CyanChat cho ("cho.cyan.com", 1813);
   cho.setDebug(true);

   // Show the config
   cho.showConfig();

   // Connect
   cho.connect();
}

CyanChat.h - Class descriptor for CyanChat class

Code:
#ifndef CYANCHAT_H
#define CYANCHAT_H

#include "ClientSocket.h"
#include "SocketException.h"

class CyanChat
{
   // Private variables
   char host[255];
   unsigned int port;
   bool connected;
   bool loggedin;
   bool debugMode;
   char nick[20];
//   ClientSocket socket;

   // Private functions
   void init();
   void debug(const char *line);

public:
   //////////////////
   // Constructors //
   //////////////////
   CyanChat();
   CyanChat(const char *host);
   CyanChat(unsigned int port);
   CyanChat(const char *host,unsigned int port);

   ///////////////////
   // Configuration //
   ///////////////////
   void setDebug(bool setting);
   bool getDebug();
   void setHost(const char *host);
   void setPort(unsigned int port);
   void showConfig();

   ////////////////////
   // Public Methods //
   ////////////////////
   void connect();
};

#endif

CyanChat.cpp - Implementation of my class

Code:
#include <iostream>
#include <cstring> // for strncpy
#include <assert.h>
#include "CyanChat.h"

// RudeSocket
#include "ClientSocket.h"
#include "SocketException.h"

/******************************************************************************
 * Object Constructors                                                        *
 ******************************************************************************/

CyanChat::CyanChat()
{
   // Set the default settings
   init();
   setHost("cho.cyan.com");
   setPort(1812);
}

CyanChat::CyanChat(const char *host,unsigned int port)
{
   // Set the hostname AND port
   init();
   setHost(host);
   setPort(port);
}

CyanChat::CyanChat(const char *host)
{
   // Set just the hostname
   init();
   setHost(host);
}

CyanChat::CyanChat(unsigned int port)
{
   // Set just the port
   init();
   setPort(port);
}

void CyanChat::init()
{
   // Initialize everything
   connected = false;
   loggedin  = false;
   debugMode = false;
}

void CyanChat::debug(const char *line)
{
   using namespace std;
   if (debugMode)
   {
      char debug[255];
      strncpy(debug, line, 255);
      cout << debug << endl;
   }
}

/******************************************************************************
 * Configuration                                                              *
 ******************************************************************************/

void CyanChat::setDebug(bool setting)
{
   debugMode = setting;
}

bool CyanChat::getDebug()
{
   return debugMode;
}

void CyanChat::setHost(const char *host)
{
   debug("Setting hostname");
   strncpy(this->host, host, 255);
}

void CyanChat::setPort(unsigned int port)
{
   debug("Setting port number");
   this->port = port;
}

void CyanChat::showConfig()
{
   using namespace std;
   cout << "Current Configuration\n"
      << "Hostname: " << this->host << "\n"
      << "    Port: " << this->port << "\n";
}

/******************************************************************************
 * Public Methods                                                             *
 ******************************************************************************/

//rude::Socket *CyanChat::socket = new rude::Socket();

void CyanChat::connect()
{
   assert(!connected);
   debug("Connecting to cho...");
//   ClientSocket socket (host, port);
   connected = true;
   debug("Connected!");
}

The problem is in CyanChat.h, at the "ClientSocket socket" line. ClientSocket (the socket code I tried last, which I got from here: has a constructor that wants to be initialized with a host and port. So using a simple "ClientSocket socket" here throws an error when I compile it:

Code:
CyanChat.cpp: In constructor \u2018CyanChat::CyanChat()\u2019:
CyanChat.cpp:14: error: no matching function for call to \u2018ClientSocket::ClientSocket()\u2019
ClientSocket.h:13: note: candidates are: ClientSocket::ClientSocket(std::string, int)
ClientSocket.h:10: note:                 ClientSocket::ClientSocket(const ClientSocket&)

If I comment the line out, as I did in the code here, the error goes away.

The idea is that the "socket" variable be a class-level variable of a ClientSocket type, but it shouldn't be initialized until connect() is called.

I've also tried using Rude Socket, with less success. The one example on this page: has them creating it as a regular object (rude::Socket socket), but then all of the examples in the API reference use a dynamic pointer (Socket *socket = new Socket).

If I adjust my code so that the socket is declared in the header file as "rude::Socket socket;", it throws this error:

Code:
/tmp/ccmJARLK.o: In function `CyanChat::~CyanChat()':
CCBot.cpp:(.text._ZN8CyanChatD1Ev[CyanChat::~CyanChat()]+0x12): undefined reference to `rude::Socket::~Socket()'
/tmp/ccf4XIJr.o: In function `CyanChat::CyanChat()':
CyanChat.cpp:(.text+0x14): undefined reference to `rude::Socket::Socket()'
CyanChat.cpp:(.text+0x50): undefined reference to `rude::Socket::~Socket()'

If I change the declaration to use *socket like a pointer it will compile with no errors. But if I try to initialize it in connect(), i.e.

Code:
*socket = new rude::Socket();

Error:
CyanChat.cpp: In member function \u2018void CyanChat::connect()\u2019:
CyanChat.cpp:109: error: no match for \u2018operator=\u2019 in \u2018*((CyanChat*)this)->CyanChat::socket = (operator new(4u), (<statement>, ((rude::Socket*)<anonymous>)))\u2019
/usr/include/rude/socket.h:114: note: candidates are: rude::Socket& rude::Socket::operator=(const rude::Socket&)

socket = new rude::Socket();

Error:
/tmp/ccCFqV6e.o: In function `CyanChat::connect()':
CyanChat.cpp:(.text+0x370): undefined reference to `rude::Socket::Socket()'
collect2: ld returned 1 exit status

So, how can I resolve this? If I can't declare a variable of type ClientSocket, is there a way for connect() to somehow "export" its own ClientSocket variable up to the class level, so that other functions I add later like send() can access it?

Thanks in advance.

Cuvou.com | My personal homepage
Code:
perl -e '$|=$i=1;print" oo\n<|>\n_|_";x:sleep$|;print"\b",$i++%2?"/":"_";goto x;'
 
ClientSocket case:

Declare a pointer to ClientSocket member then create an object of ClientSocket in connect:
Code:
private:
  ClientSocket* pSocket;
  ...
};

CyanChat::CyanChat(): pSocket(0), ...
{
  ...
}
...
void CyanChat::connect()
{
  ...
  pSocket = new ClientSocket(host,port); 
  ...
}
...
CyanChat::~CyanChat()
{
  ...
  delete pSocket;
  ...
}
Don't forget to delete the pointer in CyanChat destructor.

It's a rather strange interface for the socket wrapper ClientSocket if you can't declare ClientSocket without host and port...

Regrettably I have no time to look into the 2nd case...
 
Hmm.

This didn't get me anywhere - I still got the same errors about references.

I took a second look at rudesocket, apparently if the program is compiled with "-lrudesocket" in the command line arguments, it compiles without error.

So this works now:

Code:
class CyanChat
{
   rude::Socket *socket;

...

void CyanChat::connect()
{
   socket = new rude::Socket();
   socket->connect(host,port);

...

void CyanChat::~CyanChat()
{
   delete socket;
}

Thanks.

Cuvou.com | My personal homepage
Code:
perl -e '$|=$i=1;print" oo\n<|>\n_|_";x:sleep$|;print"\b",$i++%2?"/":"_";goto x;'
 
That's OK but you can't get "the same errors about references" in my variant with ClientSocket. Your snippet with rude::Socket follows the same pattern ;)
 
The part about your code snippit that I didn't understand was:

Code:
CyanChat::CyanChat(): pSocket(0), ...

So I just put the ": pSocket(0)" bit there - it might've had to do with the error. So my working snippit doesn't have such a line.

I think the biggest problem is that the old lib I was trying to use didn't like being used the same way that rude::Socket does.

I still have a lot to learn about C++. :)

Cuvou.com | My personal homepage
Code:
perl -e '$|=$i=1;print" oo\n<|>\n_|_";x:sleep$|;print"\b",$i++%2?"/":"_";goto x;'
 
The :pSocket(0) construct is so called ctor-initializer. It initializes member variables (assign null pointer value to pSocket in that case). See, for example:

Program logic:
As far as you have not ClientSocket default constructor (without parameters) and no proper ClientSocket ctor arguments at the moment of CyanChat instantiation, you can't declare ClientSocket member in CyanChat. But you can declare a pointer to a ClientSocket object then create the ClientSocket object dynamically at the proper moment.

It's a very common programming case.

Good luck!
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top