I find myself constantly running into a situation where I have a set of messages that I need to send over a TCP/IP connection. I have never found a good solution for the design of the message class. I would like to have a message base class where all messages derive from it. Since each message will have different fields, this would allow me to access the fields through member variables or methods. Something like...
class message_base
{
public:
message_base();
virtual ~message_base();
unsigned int type;
};
class message_control : public message_base
{
public:
message_control();
virtual ~message_control();
unsigned int action;
};
This way I can create a message_control and access the action member for assigning to and reading from. I can also pass the messages around without writing too much code.
The problem arises when I need to send the messages. If I override the operator<< and operator>> then I can send the messages over one variable at a time. The problem with that solution is that with so many calls to send data, the context switches will slam the processor. Also, the streaming operator ends up the the socket class and not in the message class where I would prefer it lived.
socket& socket::operator<<(message_control& message)
{
sock << type;
sock << action;
}
If I pack the data in a buffer, I get away from C++ and more into the realm of C and find myself making generous use of pointers and the like. And, modifying the code is difficult and error prone. And, the streaming operator is still in the socket class and not the message class.
socket& socket::operator<<(message_control& message)
{
byte* buffer = new byte[sizeof(message.type) + sizeof(message.action)];
memcpy(buffer, message.type, sizeof(message.type));
memcpy(buffer + sizeof(message.type), message.action, sizeof(message.action));
sock.send(buffer);
}
My last attempt used an intermediate class to handle packing and unpacking the members in a buffer. The messages could implement operator<< and operator>> to the buffer class and then the buffer class is sent to the socket. This works but doesn't feel right.
class socket
{
public:
socket();
~socket();
socket& operator<<(buffer& buff);
};
class buffer
{
public:
buffer() {m_buffer = new byte[initial_size];}
~buffer() {delete [] m_buffer;}
buffer& operator<<(unsigned int value);
private:
byte* m_buffer;
};
void message_control::serialize(buffer& buff)
{
buff << type;
buff << action;
}
I can't help but feel there is an elegant solution to this problem. I can't find any design patterns that match what I am trying to accomplish. Has anyone experienced this problem and come up with a going design that doesn't make you feel like you would be better off with good old pointers and an array of bytes?
Update
I failed to mention in my original post that I am most often dealing with very well define wire protocols. That is why I typically need to roll my own solution and can't use any of the wonderful toolkits available for messaging over a network connection.
"The problem with that solution is that with so many calls to send data, the context switches will slam the processor. Also, the streaming operator ends up the the socket class and not in the message class where I would prefer it lived."
The solution to the second problem is to define operator<< as a non-member function in the namespace which contains the message class, instead of as a member function of the socket class. ADL will find it.
The solution to the first problem is to buffer the data within your process, and then flush at the end of each message. If Nagle buffering isn't preventing context switches, then you might be able to achieve this by messing with the socket, I don't know. What you certainly can do, though, is prepare each message before sending in a more C++-ish way. Replace:
sock << type;
sock << action;
with:
stringstream ss;
ss << type;
ss << action;
sock << ss.str();
Related
I apologize for the ambiguous title, but I'll try to elaborate further here:
I have an application which includes (among others) a control, and TCP server classes.
Communication between the TCP and control class is done via this implementation:
#include <boost/signals2.hpp>
// T - Observable object type
// S - Function signature
template <class T, typename S> class observer {
using F = std::function<S>;
public:
void register_notifier(T &obj, F f)
{
connection_ = obj.connect_notifier(std::forward<F>(f));
}
protected:
boost::signals2::scoped_connection connection_;
};
// S - Function signature
template <typename S> class observable {
public:
boost::signals2::scoped_connection connect_notifier(std::function<S> f)
{
return notify.connect(std::move(f));
}
protected:
boost::signals2::signal<S> notify;
};
Where the TCP server class is the observable, and the control class is the observer.
The TCP server is running on a separate thread from the control class, and uses boost::asio::async_read. Whenever a message is received, the server object sends a notification via the 'notify' member, thus triggering the callback registered in the control class, and then waits to read the next message.
The problem is that I need to somehow safely and efficiently store the data currently stored in the TCP server buffer and pass it to the control class before it's overridden by the next message.
i.e. :
inline void ctl::tcp::server::handle_data_read(/* ... */)
{
if (!error) {
/* .... */
notify(/* ? */); // Using a pointer to the buffer
// would obviously fail as it
// is overridden in the next read
}
/* .... */
}
Those were my ideas for a solution so far:
Allocating heap memory and passing a pointer to it using
unique_ptr, but I'm not sure if boost.signals2 is move-aware.
Use an
unordered map (shared between the objects) that maps an integer index to a unique_ptr of the
data type (std::unordered_map<int, std::unique_ptr<data_type>>),
then only pass the index of the element, and 'pop' it in the control
class callback, but it feels like an overkill.
What I'm really looking for is an idea for a simple and efficient solution to pass the TCP buffer contents for each message between the threads.
Note I'm also open for suggestions to redesign my communication method between the objects if it's completely wrong.
I am currently trying to write the networking part of a little multiplayer game, and I am facing a problem to store my TCP sockets which are, in SFML, non-copyable (I am a beginner in C++).
I have three classes : Server, Client (a server-side class used to store all informations about a connecting client) and ClientManager, which is in charge of storing all clients and giving them IDs, etc.
ClientManager.h
class ClientManager {
public:
ClientManager();
std::map<int, Net::Client*> getClients();
int attribID();
void addClient(Net::Client *client);
sf::TcpSocket getClientSocket(int id) throw(std::string);
void setClientSocket(int id, sf::TcpSocket);
private:
std::map<int, Net::Client*> m_clients;
std::map<int, sf::TcpSocket> m_clientSockets;
std::vector<int> m_ids;
int m_lastID;
};
What I planned to do originally, when a client connects, is :
void Net::Server::waitForClient() {
while(true) {
if(m_listener.accept(m_tcpSocket) != Socket::Done) {
cout << "Error happened during client connection. skipping. " << endl;
return;
}
int newID = m_clientManager.attribID();
this->m_clientManager.addClient(new Net::Client(newID, m_tcpSocket, m_tcpSocket.getRemoteAddress()));
}
}
So, adding a new Client into ClientManager's list, with its ID, a TcpSocket to send info and his address.
But, the problem is that SFML's TcpSocket class is not copyable, which means I can't copy it to a Client like this.
I could pass it as a pointer to the original TcpSocket, but what if another client connects ? The data the pointer points to will have change and the program will bug. I do not know if this behavior will be the same with smart pointers, but I think so (but I don't master them at all).
Storing them in a std::map or std::vector causes the same problem, as they both copy the object. Storing them as pointers (in the map) to the original TcpSocket will cause the same problem as before, because the socket will change too, and the pointers will point to the same object.
How can I store my sockets without having to use references, pointers or to copy my object ?
Any help will be greatly appreciated :)
It's going to be a real pain to do without pointers. Personally I use smart pointers to manage the sockets themselves (std::vector<std::unique_ptr<sf::TcpSocket>> or similiar), along with `sf::SocketSelector' to manage the actual communication
We are leveraging POCO for our server, and making use of Poco::Net::MultipartWriter, to handle our responses for this one type of inquiry. When a client calls close on the underlying socket on their side our server crashes with an access violation however when they call shutdown on the socket this doesn't happen. I am wondering if there is something we are fundamentally doing wrong with the POCO code or if there is a better way for us to work with it to prevent this. The following is snippet of what we are doing:
class HTTPSender
{
public:
///..... Code here omitted
private:
///..... Code here omitted
void _send(CU::BorrowedPtr<const Data> Data);
Poco::Net::HTTPServerResponse& _response;
std::unique_ptr<Poco::Net::MultipartWriter> _writer;
std::ostream* _outputStream;
};
void HTTPSender::_send(BorrowedPtr<const Data> Data)
{
if(_writer == nullptr)
{
const string boundary = "myboundary";
addCommonHeaderFields(_response, HTTPResponse::HTTP_OK);
_response.setContentType(format("text/html; boundary=--%s", boundary.c_str()));
_outputStream = &_response.send();
_writer.reset(new MultipartWriter(*_outputStream, boundary));
}
MessageHeader header;
_addFrameHeaderFields(&header, Data);
header.add(HTTPMessage::CONTENT_TYPE, _getContentType(Data->Format));
header.add(HTTPMessage::CONTENT_LENGTH, to<string>(Data->length));
_writer->nextPart(header);
_outputStream->write((const char*)Data->buffer, (std::streamsize)Data->length);
}
The send method is called every time we have more of our data available which happens on a periodic interval. The Access violation always occurs in the _outputStream::write method. And given that it only happens when the client call close as opposed to shutdown it makes me think we need to adjust our approach. Additionally I have inspected the ostream::good flag before and after the debugger breaks on the access violation but in both cases it is true.
Thank you!
I have a question for you.
I have this class:
`
#define DIMBLOCK 128
#ifndef _BLOCCO_
#define _BLOCCO_
class blocco
{
public:
int ID;
char* data;
blocco(int id);
};
#endif
blocco::blocco(int id)
{
ID = id;
data = new char[DIMBLOCK];
}
`
and the application has a client and a server.
In the main of my server I instantiate an object of this class in this way:
blocco a(1);
After that I open a connection between the client and the server using sockets.
The question is: how can I send this object from the server to the client or viceversa?
Could you help me please?
It's impossible to send objects across a TCP connection in the literal sense. Sockets only know how to transmit and receive a stream of bytes. So what you can do is send a series of bytes across the TCP connection, formatted in such a way that the receiving program knows how to interpret them and create an object that is identical to the one the sending program wanted to send.
That process is called serialization (and deserialization on the receiving side). Serialization isn't built in to the C++ language itself, so you'll need some code to do it. It can be done by hand, or using XML, or via Google's Protocol Buffers, or by converting the object to human-readable-text and sending the text, or any of a number of other ways.
Have a look here for more info.
you can do this using serialization. This means pulling object into pieces so you can send these elements over the socket. Then you need to reconstruct your class in the other end of connection. in Qt there is QDataStream class available providing such functionality. In combination with a QByteArray you can create a data package which you can send. Idea is simple:
Sender:
QByteArray buffer;
QDataStream out(&buffer);
out << someData << someMoreData;
Receiver:
QByteArray buffer;
QDataStream in(&buffer);
in >> someData >> someMoreData;
Now you might want to provide additional constructor:
class blocco
{
public:
blocco(QDataStream& in){
// construct from QDataStream
}
//or
blocco(int id, char* data){
//from data
}
int ID;
char* data;
blocco(int id);
};
extended example
I don't know how much flak I'll get for this, but well I tried this and though I should share it. I am a beginner at socket programming so don't get pissed off.
What I did is I created an array of characters which is of the size of the class (representing the block of memory at the server side). Then I recved the block of memory at the client side and typecast that block of memory as an object and voila!! I managed to send an object from client to server.
Sample code:
blocco *data;
char blockOfData[sizeof(*data)];
if(recv(serverSocket, blockOfData, sizeof(*data), 0) == -1) {
cerr << "Error while receiving!!" << endl;
return 1;
}
data = (blocco *)blockOfData;
Now you can do whatever you want with this data using this as a pointer to the object. Just remember do not try to delete/free this pointer as this memory is assigned to the array blockOfData which is on the stack.
Hope this helps if you wanted to implement something like this.
PS: If you think what I've done is poor way of coding please let me know why. I don't know why this is such a bad idea(if it is in fact a bad idea to do this). Thanks!!
Okay, I actually don't have code as of yet because i'm just picking out a framework for the time being, but i'm still a little baffled about how i wish to go about this :.
Server side, i wish to have a class where each instance has a socket and various information identifying each connection. each object will have it's own thread for receiving data. I understand how i'll be implementing most of that, but my confusion starts just as i get to the actual transfer of data between server and client. I'll want to have a bunch of different message structs for specific cases, (for example CONNECT_MSG , DISCONNECT_MSG, POSTTEXT_MSG, etc) and then all i have to do is have a char * point at that struct and then pass it via the send() function.
But as i think on it, it gets a little complicated at that point. Any of those different message types could be sent, and on the receiving end, you will have no idea what you should cast the incoming buffer as. What i was hoping to do is, in the thread of each connection object, have it block until it receives a packet with a message, then dump it into a single queue object managed by the server(mutexes will prevent greediness) and then the server will process each message in FIFO order independent of the connection objects.
I havn't written anything yet, but let me write a little something to illustrate my setup.
#define CONNECT 1000
struct GENERIC_MESSAGE
{
int id;
}
struct CONNECT_MESSAGE : public GENERIC_MESSAGE
{
m_username;
}
void Connection::Thread()
{
while(1)
{
char buffer[MAX_BUFFER_SIZE]; // some constant(probably 2048)
recv(m_socket, buffer, MAX_BUFFER_SIZE, 0);
MESSAGE_GENERIC * msg = reinterpret_cast<MESSAGE_GENERIC *> (buffer);
server->queueMessage(msg);
}
}
void Server::QueueMessage(MESSAGE_GENERIC * msg)
{
messageQueue.push(msg);
}
void Server::Thread()
{
while(1)
{
if(!messageQueue.empty())
ProcessMessages();
else
Sleep(1);
}
}
void Server::ProcessMessages()
{
for(int i = 0; i < messageQueue.size(); i++)
{
switch(messageQueue.front()->id)
{
case CONNECT:
{
// the part i REALLY don't like
CONNECT_MESSAGE * msg = static_cast<CONNECT_MESSAGE *>(messageQueue.front() );
// do the rest of the processing on connect
break;
}
// other cases for the other message types
}
messageQueue.pop();
}
}
Now if you've been following up until now, you realize just how STUPID and fragile this is. it casts to the base class, passes that pointer to a queue, and then just assumes that the pointer is still valid from the other thread, and even then whether or not the remaining buffer after the pointer for the rest of the derived class will always be valid afterward for casting, but i have yet to find a correct way of doing this. I am wide open for ANY suggestions, either making this work, or an entirely different messaging design.
Before you write even a line of code, design the protocol that will be used on the wired. Decide what a message will consist of at the byte level. Decide who sends first, whether messages are acknowledged, how receivers identify message boundaries, and so on. Decide how the connection will be kept active (if it will be), which side will close first, and so on. Then write the code around the specification.
Do not tightly associate how you store things in memory with how you send things on the wire. These are two very different things with two very different sets of requirements.
Of course, feel free to adjust the protocol specification as you write the code.