Чтение онлайн

ЖАНРЫ

QT 4: программирование GUI на С++

Саммерфилд Марк

Шрифт:

05 stopButton->setEnabled(false);

06 progressBar->hide;

07 }

Закрытая функция closeConnection закрывает соединение сервера TCP и обновляет интерфейс пользователя. Она вызывается из функции updateTableWidget, когда считывается значение 0xFFFF, и из нескольких других слотов, которые мы вскоре рассмотрим.

01 void TripPlanner::stopSearch

02 {

03 statusLabel->setText(tr("Search stopped"));

04 closeConnection;

05 }

Слот stopSearch подсоединяется

к сигналу clicked кнопки Stop. По существу, он просто вызывает функцию closeConnection.

01 void TripPlanner::connectionClosedByServer

02 {

03 if (nextBlockSize != 0xFFFF)

04 statusLabel->setText(tr("Error: Connection closed by server" ));

05 closeConnection;

06 }

Слот connectionClosedByServer подсоединяется к сигналу disconnected объекта QTcpSocket. Если сервер закрывает соединение и мы еще не получили маркер конца, мы уведомляем пользователя о возникновении ошибки. И как обычно, мы вызываем функцию closeConnection для обновления интерфейса пользователя.

01 void TripPlanner::error

02 {

03 statusLabel->setText(tcpSocket.errorString);

04 closeConnection;

05 }

Слот error подсоединяется к сигналу error(QAbstractSocket::SocketError) объекта QTcpSocket. Мы игнорируем код ошибки и используем функцию QTcpSocket::errorString, которая возвращает понятное человеку сообщение о последней возникшей ошибке.

На этом завершается рассмотрение класса TripPlanner. Функция main приложения Trip Planner выглядит обычным образом:

01 int main(int argc, char *argv[])

02 {

03 QApplication app(argc, argv);

04 TripPlanner tripPlanner;

05 tripPlanner.show;

06 return app.exec;

07 }

Теперь давайте реализуем сервер. Сервер состоит из двух классов: TripServer и ClientSocket. Класс TripServer наследует QTcpServer — класс, который позволяет нам принимать входящие соединения TCP. Класс ClientSocket переопределяет QTcpSocket и обслуживает одно соединение. В каждый момент времени в памяти имеется ровно столько объектов типа ClientSocket, сколько обслуживается клиентов.

01 class TripServer : public QTcpServer

02 {

03 Q_OBJECT

04 public:

05 TripServer(QObject *parent = 0);

06 private:

07 void incomingConnection(int socketId);

08 };

Класс TripServer переопределяет функцию incomingConnection из

класса QTcpServer. Данная функция вызывается всякий раз, когда клиент пытается подсоединиться к порту, который прослушивает сервер.

01 TripServer::TripServer(QObject *parent)

02 : QTcpServer (parent)

03 {

04 }

Конструктор TripServer тривиален.

01 void TripServer::incomingConnection(int socketId)

02 {

03 ClientSocket *socket = new ClientSocket(this);

04 socket->setSocketDescriptor(socketId);

05 }

В функции incomingConnection мы создаем объект ClientSocket в качестве дочернего по отношению к объекту TripServer, и мы устанавливаем дескриптор его coкета на переданное нам значение. Объект ClientSocket автоматически удалит сам себя при прекращении соединения.

01 class ClientSocket : public QTcpSocket

02 {

03 Q_OBJECT

04 public:

05 ClientSocket(QObject *parent = 0);

06 private slots:

07 void readClient;

08 private:

09 void generateRandomTrip(const QString &from, const QString &to,

10 const QDate &date, const QTime &time);

11 quint16 nextBlockSize;

12 };

Класс ClientSocket наследует QTcpSocket и инкапсулирует состояние одного клиента.

01 ClientSocket::ClientSocket(QObject *parent)

02 : QTcpSocket(parent)

03 {

04 connect(this, SIGNAL(readyRead), this, SLOT(readClient));

05 connect(this, SIGNAL(disconnected), this, SLOT(deleteLater));

06 nextBlockSize = 0;

07 }

В конструкторе мы устанавливаем необходимые соединения сигнал—слот и задаем переменной nextBlockSize значение 0, свидетельствующее о том, что мы еще не знаем размер посланного клиентом блока.

Сигнал disconnected подсоединяется к функции deleteLater, которая наследуется от класса QObject, и удаляет объект после возврата управления в цикл обработки событий Qt. Это обеспечивает удаление объекта ClientSocket после закрытия сокетного соединения.

01 void ClientSocket::readClient

02 {

03 QDataStream in(this);

04 in.setVersion(QDataStream::Qt_4_1);

05 if (nextBlockSize == 0) {

06 if (bytesAvailable < sizeof(quint16))

07 return;

08 in >> nextBlockSize;

09 }

10 if (bytesAvailable < nextBlockSize)

11 return;

12 quint8 requestType;

Поделиться с друзьями: