Клиент-серверныйт чат на Qt

Всем привет. У меня возникла проблема с которой уже не могу справиться несколько дней. Я новичок на в сетевом программировании и Qt, поэтому если что не кидайтесь камнями) Проблема в том, что я не могу отправить собщение всем клиентам, которые подключились к моему серверу. Не понимаю в чем проблема. У меня будет только один чат-рум, я читала, что тут многопоточности не надо. Не получилось без нее сделать. Сделала с многопоточностью - все равно не получаеться отправить сообщение всем потокам. Надо чтобы я например отправляла сообщение, и оно было видно всем клиентам, которые тоже находятся в этом чат-руме. Заранее спасибо за ответ.

//server.h
#ifndef SERVER_H
#define SERVER_H

#include <QtNetwork>
#include <QTcpServer>
#include <QTcpSocket>
#include <QObject>
#include "thread.h"
class Server : public QObject
{
    Q_OBJECT
public:
     Server(QObject *parent = 0);
    ~Server();
    QVector<QTcpSocket*> sockets;
    QTcpSocket *socket;
    QTcpServer *tcpServer;
    QByteArray Data; //дані які ми будемо відправляти по сокету в мережу
public slots:
    void Connection(); //опис дій  в випадку підключення нового клієнта
    //socket_fd - унікальний номер нашого зєднання
    void sockReady();//готовність сокета читати дані
    void sockDisc(); //відключення клієнта від сокета
};

#endif // SERVER_H
//server.cpp
#include "server.h"
#include "thread.h"
Server::Server(QObject *parent) : QObject(parent)
{
    tcpServer = new QTcpServer(this);
    connect(tcpServer, &QTcpServer::newConnection,this,&Server::Connection);
    if(tcpServer->listen(QHostAddress::Any,7300))//QHostAdress - адреса по якій запущений сервер
    {
        qDebug()<<"Listening...";
    }
    else
    {
        qDebug()<<"Not listening";
    }
}
Server::~Server(){}

void Server::Connection()
{
    socket = tcpServer->nextPendingConnection();
    Thread *thread = new Thread(socket->socketDescriptor(),this);
    sockets.push_back(socket);
    connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
  //  connect(thread, SIGNAL(disconnected()), thread, SLOT(sockDisc()), Qt::DirectConnection);
    thread->start();
    qDebug() << "Client connected";
    socket->write("You are connect");
}
void Server::sockReady()
{
    while(socket->bytesAvailable()>0)
    {
        QByteArray array = socket->readAll();
        for(auto el : sockets)
        {
            if(el != socket)
                el->write(array);
        }
        //socket->write(array);
        qDebug()<<array<<"\n";
    }
}
void Server::sockDisc() //disconnect
{
    qDebug()<<"Disconnect";
    socket->close();
}
//thread.h
#ifndef THREAD_H
#define THREAD_H

#include <QThread>
#include <QTcpSocket>
#include <QTcpServer>
#include <QDebug>

class Thread : public QThread
{
    Q_OBJECT
public:
    explicit Thread(int ID, QObject *parent=0);
    void run();

signals:
    void error(QTcpSocket::SocketError sockerror);
private:
    QTcpSocket *socket;
    int socketDescriptor;
public slots:
    void readyRead();
    void disconnected();
};

#endif // THREAD_H
//thread.cpp
#include "thread.h"

Thread::Thread(int ID, QObject *parent) : QThread(parent)
{
    this->socketDescriptor=ID;

}
void Thread::run()
{
    qDebug()<<"Starting thread";
    socket=new QTcpSocket();
    if(!socket->setSocketDescriptor(this->socketDescriptor))
    {
        emit error(socket->error());
        return;
    }
    connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()), Qt::DirectConnection);
    connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected()), Qt::DirectConnection);

    qDebug()<<socketDescriptor<<" Client connected!";
    exec();

}
void Thread::readyRead()
{
    QByteArray Data = socket->readAll();
    qDebug()<<socketDescriptor<<" Data in "<<Data;
    socket->write(Data);
}
void Thread::disconnected()
{
    qDebug()<<socketDescriptor<<" Disconnected ";
    socket->deleteLater();
    exit(0);
}
//main.cpp
#include <QCoreApplication>
#include <QtNetwork>
#include <QTcpServer>
#include <QTcpSocket>
#include "server.h"
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    Server server;
    return a.exec();
}

Ответы (1 шт):

Автор решения: Rikitikitavi

Я так понимаю логика такая: клиент подключается к серверу, посылает сообщение, далее сервер пересылает это сообщение всем клиентам которые подключились раннее. Тогда вопрос по этому месту:

 void Thread::readyRead()
 {
     QByteArray Data = socket->readAll();
     qDebug()<<socketDescriptor<<" Data in "<<Data;
     socket->write(Data);
 }

Здесь происходит чтение и запись в один и тот же сокет, то есть это эхо сервер, думаю это не то что вы хотели.

Обойтись без потоков действительно можно, попробуйте переписать код примерно по такой схеме (как работает не проверял. но логика примерно такая):

 class Server : public QObject
 {
      Q_OBJECT
 public:
      Server(QObject *parent)
      {
           tcpServer = new QTcpServer(this);
           connect(tcpServer,  &QTcpServer::newConnection,this,&Server::Connection);
           if(tcpServer->listen(QHostAddress::Any,7300))//QHostAdress - адреса по якій запущений сервер
           {
                  qDebug()<<"Listening...";
           }
           else
           {
                 qDebug()<<"Not listening";
           }
      }
      ~Server();
  public slots:
      void Connection()
      {
             QTcpSocket* socket = tcpServer->nextPendingConnection();
             _clients.push_back(socket);
             qDebug() << "Client connected";
             connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()), Qt::DirectConnection);
             connect(socket, SIGNAL(disconnected()), socket, SLOT(deleteLater()), Qt::DirectConnection);

             socket->write("You are connect");
      }
      void readyRead()
      {
          QTcpSocket* socket = QObject::sender();
          QByteArray data = socket->readAll();
          qDebug()<<socket->socketDescriptor()<<" Data in "<< data;
          for(auto client: _clients)
          {
              if (client != socket)
                 client->write(data);
          }
      }
      void sockDisc()
      {

      }
  private:
      QVector<QTcpSocket*> _clients;
      QTcpSocket* _server;
      QTcpServer* _tcpServer;
};

При подключении новый сокет клиента заносится в контейнер, и сигнал о поступлении новых данных связывается с Server::readyRead() в котором мы получаем указатель отправителя (сокет с которого пришли данные) и проходимся по всем другим сокетам-клиентам отправляя пришедшие данные. Ну или вот так, если нужен эхо сервер

      void readyRead()
      {
          QTcpSocket* socket = QObject::sender();
          QByteArray data = socket->readAll();
          qDebug()<<socket->socketDescriptor()<<" Data in "<< data;
          socket->write(Data);
      }
→ Ссылка