项目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()
{
}