INTELLIGENT WORK FORUMS
FOR COMPUTER PROFESSIONALS

Log In

Come Join Us!

Are you a
Computer / IT professional?
Join Tek-Tips Forums!
  • Talk With Other Members
  • Be Notified Of Responses
    To Your Posts
  • Keyword Search
  • One-Click Access To Your
    Favorite Forums
  • Automated Signatures
    On Your Posts
  • Best Of All, It's Free!

*Tek-Tips's functionality depends on members receiving e-mail. By joining you are opting in to receive e-mail.

Posting Guidelines

Promoting, selling, recruiting, coursework and thesis posting is forbidden.

Jobs

Class that uses sockets as a private class variable

Class that uses sockets as a private class variable

Class that uses sockets as a private class variable

(OP)
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 - http://cho.cyan.com/chat/protocol1.html

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: http://www.cuvou.com/projects/Java/JavaCC-0.01/src/org/kirsle/cyanchat/)

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: http://linuxgazette.net/issue74/tougher.html) 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: http://rudeserver.com/socket/usage.html 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;'

RE: Class that uses sockets as a private class variable

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...
 

RE: Class that uses sockets as a private class variable

(OP)
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;'

RE: Class that uses sockets as a private class variable

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 ;)
 

RE: Class that uses sockets as a private class variable

(OP)
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++. smile

Cuvou.com | My personal homepage

CODE

perl -e '$|=$i=1;print" oo\n<|>\n_|_";x:sleep$|;print"\b",$i++%2?"/":"_";goto x;'

RE: Class that uses sockets as a private class variable

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:
http://www.learncpp.com/cpp-tutorial/101-constructor-initialization-lists/

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!
 

Red Flag This Post

Please let us know here why this post is inappropriate. Reasons such as off-topic, duplicates, flames, illegal, vulgar, or students posting their homework.

Red Flag Submitted

Thank you for helping keep Tek-Tips Forums free from inappropriate posts.
The Tek-Tips staff will check this out and take appropriate action.

Reply To This Thread

Posting in the Tek-Tips forums is a member-only feature.

Click Here to join Tek-Tips and talk with other members!

Resources

Close Box

Join Tek-Tips® Today!

Join your peers on the Internet's largest technical computer professional community.
It's easy to join and it's free.

Here's Why Members Love Tek-Tips Forums:

Register now while it's still free!

Already a member? Close this window and log in.

Join Us             Close