【Qt5开发及实例】33、多线程网络时间服务器

本文详细介绍了如何使用Qt5开发多线程网络时间服务器,包括界面设计、线程处理、时间同步等功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

项目TimeServer

dialog.h

/**
* 书本:【Qt5开发及实例】
* 功能:多线程网络时间服务器
* 文件:dialog.h
* 时间:2015年2月11日22:43:26
* 作者:cutter_point
*/
#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include <QLabel>
#include <QPushButton>

class TimeServer;

class Dialog : public QDialog
{
  Q_OBJECT

public:
  Dialog(QWidget *parent = 0);
  ~Dialog();

public slots:
  void slotShow();    //线程在界面的显示

private:
  //对应的一些界面控件
  QLabel *Label1;
  QLabel *Label2;
  QPushButton *quitBtn;
  TimeServer *timeServer;   //每个界面有一个私有时间线程
  int count;    //计数
};

#endif // DIALOG_H


dialog.cpp

/**
* 书本:【Qt5开发及实例】
* 功能:多线程网络时间服务器
* 文件:dialog.cpp
* 时间:2015年2月11日22:43:26
* 作者:cutter_point
*/
#include "dialog.h"
#include "timeserver.h"

#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QMessageBox>

Dialog::Dialog(QWidget *parent)
  : QDialog(parent)
{
  this->setWindowTitle(tr("多线程时间服务器"));

  Label1 = new QLabel(tr("服务器端口:"));
  Label2 = new QLabel;

  quitBtn = new QPushButton(tr("close"));
  QHBoxLayout *BtnLayout = new QHBoxLayout;   //这个是横向的布局
  BtnLayout->addStretch(1);   //一个弹簧
  BtnLayout->addWidget(quitBtn);
  BtnLayout->addStretch(1);   //一个弹簧

  QVBoxLayout *mainLayout = new QVBoxLayout(this);    //列的方向
  mainLayout->addWidget(Label1);
  mainLayout->addWidget(Label2);
  mainLayout->addLayout(BtnLayout);

  connect(quitBtn, SIGNAL(clicked()), this, SLOT(close()));

  //有一个计数器
  count = 0;
  //创建一个时间服务器
  timeServer = new TimeServer(this);
  //监听所有的时间服务器的端口和地址
  //监听失败的话
  if(!timeServer->listen())
    {
      QMessageBox::critical(this, tr("多线程时间服务器"), tr("无法启动服务器:%1.").arg(timeServer->errorString()));
      close();
      return;
    }


  //监听成功,输出有动静的端口号
  Label1->setText(tr("服务器端口:   %1").arg(timeServer->serverPort()));
}

//void slotShow();    //线程在界面的显示,线程结束的时候调用
void Dialog::slotShow()
{
  //显示这是第几次请求,也就是第几次调用线程执行这个函数
  Label2->setText(tr("第%1次请求完毕.").arg(++count));
}

Dialog::~Dialog()
{

}


timeserver.h

/**
* 书本:【Qt5开发及实例】
* 功能:多线程网络时间服务器
* 文件:timeserver.h
* 时间:2015年2月11日23:17:43
* 作者:cutter_point
*/
#ifndef TIMESERVER_H
#define TIMESERVER_H

#include <QTcpServer>

class Dialog;

class TimeServer : public QTcpServer
{
  Q_OBJECT
public:
  explicit TimeServer(QObject *parent = 0);

signals:

public slots:

protected:
  void incomingConnection(int socketDescriptor);    //当tcp有新的连接的时候调用,其参数为所接收新连接的套接字描述符

private:
  Dialog *dlg;    //界面

};

#endif // TIMESERVER_H


timeserver.cpp

/**
* 书本:【Qt5开发及实例】
* 功能:多线程网络时间服务器
* 文件:timeserver.cpp
* 时间:2015年2月11日23:18:08
* 作者:cutter_point
*/
#include "timeserver.h"
#include "timethread.h"
#include "dialog.h"

TimeServer::TimeServer(QObject *parent) :
  QTcpServer(parent)
{
  //初始化界面
  dlg = (Dialog *)parent; //转化为dialog前面的对象的指针
}

//void incomingConnection(int socketDescriptor);    //当tcp有新的连接的时候调用,其参数为所接收新连接的套接字描述符
void TimeServer::incomingConnection(int socketDescriptor)
{
  //有一个新连接的时候,就相应的创建一个对应的线程
  TimeThread *thread = new TimeThread(socketDescriptor);

  //线程结束的时候,要通知界面的显示
  connect(thread, SIGNAL(finished()), dlg, SLOT(slotShow()));
  //同时销毁结束线程
  connect(thread, SIGNAL(finished()), dlg, SLOT(deleteLater()));

  //启动线程
  thread->start();
}






timethread.h


/**
* 书本:【Qt5开发及实例】
* 功能:多线程网络时间服务器
* 文件:timethread.h
* 时间:2015年2月11日22:43:26
* 作者:cutter_point
*/
#ifndef TIMETHREAD_H
#define TIMETHREAD_H

#include <QThread>
#include <QtNetwork>
#include <QTcpSocket>

class TimeThread : public QThread
{
  Q_OBJECT
public:
  explicit TimeThread(int socketDescriptor, QObject *parent = 0);
  void run();   //继承来的,线程执行的内容

signals:
  //如果出错的话可以给出错误信息
  void error(QTcpSocket::SocketError socketError);

public slots:

private:
  int socketDescriptor;   //套接字描述符


};

#endif // TIMETHREAD_H

timethread.cpp

/**
* 书本:【Qt5开发及实例】
* 功能:多线程网络时间服务器
* 文件:timethread.cpp
* 时间:2015年2月11日22:43:26
* 作者:cutter_point
*/
#include "timethread.h"

#include <QDateTime>    //时间
#include <QByteArray>   //协议传输的字节流
#include <QDataStream>    //数据流

TimeThread::TimeThread(int socketDescriptor, QObject *parent) :
  QThread(parent), socketDescriptor(socketDescriptor)     //初始化
{
}

void TimeThread::run()    //线程执行开始的函数
{
  QTcpSocket tcpSocket;     //创建一个tcp套接字
  if(!tcpSocket.setSocketDescriptor(socketDescriptor))    //如果套接字描述符操作失败
    {
      emit error(tcpSocket.error());    //发出错误信号
      return;   //结束
    }

  QByteArray block;   //字节数组,这个block应该是一个指向第一个位置的指针
  QDataStream out(&block, QIODevice::WriteOnly);    //数据流,数据流操作block,这里block指针??
  out.setVersion(QDataStream::Qt_5_3);    //版本= =

  uint time2u = QDateTime::currentDateTime().toTime_t();    //得到系统的时间,并传换成时间的格式
  out<<time2u;    //输入到字节流中

  tcpSocket.write(block);   //把字节流写到协议端口
  tcpSocket.disconnectFromHost();   //断开端口连接
  tcpSocket.waitForDisconnected();    //默认时间,等待客户端返回信息

}








项目TimeClient


timeclient.h

/**
* 书本:【Qt5开发及实例】
* 功能:多线程网络时间服务器
* 文件:timeclient.h
* 时间:2015年2月11日23:49:56
* 作者:cutter_point
*/
#ifndef TIMECLIENT_H
#define TIMECLIENT_H

#include <QDialog>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QDateTimeEdit>
#include <QTcpSocket>
#include <QAbstractSocket>

class TimeClient : public QDialog
{
  Q_OBJECT

public:
  TimeClient(QWidget *parent = 0);
  ~TimeClient();
public slots:
    void enableGetBtn();    //按钮的控制
    void getTime();   //准备得到时间
    void readTime();    //读取时间过来
    void showError(QAbstractSocket::SocketError socketError);   //出错
private:
    QLabel *serverNameLabel;
    QLineEdit *serverNameLineEdit;
    QLabel *portLabel;
    QLineEdit *portLineEdit;
    QDateTimeEdit *dateTimeEdit;    //显示时间的控件
    QLabel *stateLabel;   //状态表示

    QPushButton *getBtn;
    QPushButton *quitBtn;

    uint time2u;    //得到的时间
    QTcpSocket *tcpSocket;      //tcp套接字
};

#endif // TIMECLIENT_H


timeclient.cpp

/**
* 书本:【Qt5开发及实例】
* 功能:多线程网络时间服务器
* 文件:timeclient.cpp
* 时间:2015年2月11日23:49:56
* 作者:cutter_point
*/
#include "timeclient.h"

#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QGridLayout>
#include <QDataStream>
#include <QMessageBox>

TimeClient::TimeClient(QWidget *parent)
  : QDialog(parent)
{
  setWindowTitle(tr("多线程时间服务客户端"));

  serverNameLabel =new QLabel(tr("服务器名:"));
  serverNameLineEdit = new QLineEdit("Localhost");

  portLabel =new QLabel(tr("端口:"));
  portLineEdit = new QLineEdit;

  QGridLayout *layout = new QGridLayout;
  layout->addWidget(serverNameLabel,0,0);
  layout->addWidget(serverNameLineEdit,0,1);
  layout->addWidget(portLabel,1,0);
  layout->addWidget(portLineEdit,1,1);

  dateTimeEdit = new QDateTimeEdit(this);
  QHBoxLayout *layout1 = new QHBoxLayout;
  layout1->addWidget(dateTimeEdit);

  stateLabel =new QLabel(tr("请首先运行时间服务器!"));
  QHBoxLayout *layout2 = new QHBoxLayout;
  layout2->addWidget(stateLabel);

  getBtn = new QPushButton(tr("获取时间"));
  getBtn->setDefault(true);
  getBtn->setEnabled(false);
  quitBtn = new QPushButton(tr("close"));
  QHBoxLayout *layout3 = new QHBoxLayout;
  layout3->addStretch();
  layout3->addWidget(getBtn);
  layout3->addWidget(quitBtn);

  QVBoxLayout *mainLayout = new QVBoxLayout(this);
  mainLayout->addLayout(layout);
  mainLayout->addLayout(layout1);
  mainLayout->addLayout(layout2);
  mainLayout->addLayout(layout3);

  connect(serverNameLineEdit,SIGNAL(textChanged(QString)),this,SLOT(enableGetBtn()));
  connect(portLineEdit,SIGNAL(textChanged(QString)),this,SLOT(enableGetBtn()));
  connect(getBtn,SIGNAL(clicked()),this,SLOT(getTime()));   //准备好接受服务器数据的最北
  connect(quitBtn,SIGNAL(clicked()),this,SLOT(close()));

  tcpSocket = new QTcpSocket(this);
  connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(readTime()));    //从端口中得到数据
  connect(tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(showError(QAbstractSocket::SocketError)));

  portLineEdit->setFocus();   //键盘焦点对准这个控件
}

//void enableGetBtn();    //按钮的控制
void TimeClient::enableGetBtn()
{
  getBtn->setEnabled(!serverNameLineEdit->text().isEmpty()&&!portLineEdit->text().isEmpty());
}

//void getTime();   //准备得到时间
void TimeClient::getTime()
{
  //得到时间之前,按下了按钮就不能再按了
  getBtn->setEnabled(false);
  //初始化这边的时间和套接字,等会用来接收数据
  time2u = 0;
  tcpSocket->abort();
  //连接上相应的服务器和端口,准备连接
  tcpSocket->connectToHost(serverNameLineEdit->text(), portLineEdit->text().toInt());
}

//void readTime();    //读取时间过来
void TimeClient::readTime()
{
  //获得到了数据就读取
  //初始化一个数据流,对端口的套接字操作
  QDataStream in(tcpSocket);
  in.setVersion(QDataStream::Qt_5_3);   //版本!!!!
  //时间如果开始初始化为0了,那么就重新获取
  if(time2u == 0)
    {
      if(tcpSocket->bytesAvailable() < (int)sizeof(uint))
        return;   //得到的数据不和常理的话,直接结束

      in>>time2u;   //把数据输出到time2u中
    }
  //不为零,那么就继续用
  dateTimeEdit->setDateTime(QDateTime::fromTime_t(time2u));
  //按钮设置为可以按
  getBtn->setEnabled(true);
}

//void showError(QAbstractSocket::SocketError socketError);   //出错
void TimeClient::showError(QAbstractSocket::SocketError socketError)
{
  switch(socketError)
    {
    case QAbstractSocket::RemoteHostClosedError:
            break;
    case QAbstractSocket::HostNotFoundError:
         QMessageBox::information(this, tr("时间服务客户端:"),tr("主机不可达!"));
         break;
    case QAbstractSocket::ConnectionRefusedError:
         QMessageBox::information(this, tr("时间服务客户端:"),tr("连接被拒绝!"));
         break;
    default:
        QMessageBox::information(this, tr("时间服务客户端:"),tr("产生如下错误: %1.").arg(tcpSocket->errorString()));
    }
  getBtn->setEnabled(true);
}

TimeClient::~TimeClient()
{

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值