There is an implementation of the client's architecture for a game of chess, the logic of which is fully described in the Game class, which contains the fields: Board object (Board) and Piece Class Object List - Piecelist

#ifndef GAME_H #define GAME_H #include <QObject> #include "piece.h" #include "board.h" #include "rook.h" #include "knight.h" #include "bishop.h" #include "queen.h" #include "king.h" #include "pawn.h" #include <QGridLayout> #include <QByteArray> #include <QDataStream> #include <QIODevice> class Game : public QObject { Q_OBJECT public: explicit Game(QObject *parent = 0); QGridLayout* drawBoard(); void start(); void clearStyleSheet(); //QByteArray bytes; friend QDataStream &operator <<(QDataStream &out,Game &game); friend QDataStream &operator >>(QDataStream &out,Game &game); //int k; //friend QDataStream operator<<(&out, const Game &any); QList<Piece*> PieceList; Board* board; signals: public slots: void is_pressed(QPoint coord) ; private: }; #endif // GAME_H 

Now I want to send using a server implemented as a QTcpServer object of the Game class to a client (another player). I do this: 1) in the Game class I create an overload of QDataStream operators:

  QDataStream &operator <<(QDataStream &out,Game &game) { out << game; return out; } 

2) Actually call:

 Game* game=new Game(); QByteArray bytes; QDataStream out(&bytes,QIODevice::WriteOnly); out<<(*game); 

And after that the program “successfully” crashes. How to solve this issue. How to transfer a class object over the network using QtcpSocket and QDataStream?

  • For transferring objects in python, I created a wsgi server and passed data through a soap protocol. Not the topic, but suddenly a thought will push some =) For example, to work on soap, everything is clear there. ZY How to do in this case do not know. - spirit

3 answers 3

As far as I know, even passing this class, the Piece pointers from the QList <Piece *> PieceList; will not be transferred normally to the server. I don’t know if this is a problem during the transfer, but it’s better that you reconsider the interaction between the clients themselves (most likely you’ll have to transfer the Piece separately, since these are pointers).

Why don't you, for example, exchange changes in the position of specific figures?

  • one
    In fact, the exchange of portions of 4 bytes, the form of e2e4 will be quite enough for 2 programs. - avp
  • I agree. You can, of course, complicate, make the transfer of the name of the figure "p1" (pawn # 1), the initial position, the final position ... and who can she eat to check once again on the other side. But this is redundancy. - spirit

That's right. The fact that your error is popping up is very correct. The error is very simple and without underwater stones.

no match for 'operator <<' in 'out << * game.Game::board'

This is your mistake. What is she talking about? The object itself communicates with us, i.e. class QDataStream. This class tells us "There is no such overloaded function that would be able to record a game object." But this is nonsense, because you yourself overloaded the function that accepts the game object for writing, therefore, it must be recognized. It turns out that this is not nonsense at all, but the whole point is how you implemented the QDataStream & operator << function overload (QDataStream & out, Game & game).

 QDataStream &operator <<(QDataStream &out,Game &game) { out << game; return out; } 

This is your overload. When you write out << * game, the compiler searches for and finds the appropriate function (which you rebooted) and starts executing the code you wrote there. You did not write anything special there, but simply wrote out << game. So the compiler does not know how to do this for "foreign" objects. He again searches for and finds your function, and again stumbles upon the line out << game, etc. etc. In general, you need to overwrite the data that QDataStream understands in the overloaded function according to a certain structure (how to disassemble the Game object into components that the QDataStream understands and write them down) so that you can then consider these same components A certain structure to collect the object game.

Here is a simple example.

 #ifndef SIMPLE_H #define SIMPLE_H #include <QString> #include <QDataStream> class Simple { public: Simple(); Simple(int a_, int b_, QString s_); friend QDataStream &operator<<(QDataStream &out, Simple &obj); friend QDataStream &operator>>(QDataStream &in, Simple &obj); private: int a; int b; QString s; }; #endif // SIMPLE_H 

ccp:

 #include "simple.h" Simple::Simple() { } Simple::Simple(int a_, int b_, QString s_) : a(a_), b(b_), s(s_) { } QDataStream &operator <<(QDataStream &out, Simple &obj) { out << obj.a << obj.b << obj.s; /* если бы я написал, как Вы, "out << obj", то была бы опять ошибка, проверьте. */ return out; } QDataStream &operator >>(QDataStream &in, Simple &obj) { in >> obj.a >> obj.b >> obj.s; return in; } 

    And what prevents to do like this?

    We declare QByteArray, then in it I use QDataStream we read the length of the class object, storing it say in quint16, then the object itself. We send it all through write. At that end, establish a connection using the readyRead signal.

    The documentation says that it is called, not when all the information comes to the socket, but when at least something arrives. And there, already using the same QDataStream, we wait until 16 bits arrive to read the length of the message in quint16, check if everything has arrived, and only then read into the class object.

    This is how it looks:

    server.cpp

     void Widget::slotSendToClient() { QByteArray arrBlock; QDataStream clientSendStream(&arrBlock, QIODevice::WriteOnly); serverSendStream << quint16(0) << game; clientSendStream.device()->seek(0); clientSendStream << quint16(arrBlock.size() - sizeof(quint16)); tcpSocket->write(arrBlock); messageLineEdit->clear(); } 

    client.cpp

     void Widget::slotReadServer() { next_block_size = 0; QTcpSocket *tcpSocket = (QTcpSocket*)sender(); QDataStream serverReadStream(tcpSocket); while(true) { if (!next_block_size) { if (tcpSocket->bytesAvailable() < sizeof(quint16)) { break; } serverReadStream >> next_block_size; } if (tcpSocket->bytesAvailable() < next_block_size) { break; } Game game; serverReadStream >> game; next_block_size = 0; } } 
    • and what to do with pointers inside the game object? I will stay with the opinion that such a "metaclass" should not be transmitted over the network. - spirit
    • one
      Pointers need to be removed. Or invent another way. I did chess differently. I transmitted the coordinates and everything was fine. - Ukeo
    • TC, all come to the same opinion. Think about it =) or explain the reason for choosing such a method. - spirit
    • I would strongly not recommend in the GUI stream (class Widget) to perform while (true), since this can "hang up the interface". It is better to have a local buffer in the class and add data to it when it is received over the network, and when it is the right size (i.e. all the data will be accepted), it will need to be processed and cleaned - AlekseyOk
    • @ spirit, I thought about it ... and decided to pass the coordinates as QList <QPoint>. I tried. I got it. But it does not bother me that I can’t in any way overload the operator << dereference the pointer. To do this: out << * (game.board) . It gives an error: no match for 'operator <<' in 'out << * game.Game::board' What's wrong? - Denis Makarenko