Qt 多线程的应用 TCP

15 篇文章 0 订阅
1 篇文章 0 订阅

目的L:

实现一个多线程的网络时间服务器,介绍如何综合运用多线程技术编程。每当有客户请求到达是,服务器将启动一个新线程为它返回当前时间,服务完毕后这个线程将自动退出,同时,用户界面会显示当前已接收请求的次数。

输入端口号–
***在这里插入图片描述
点击获取时间,程序会向服务器请求一次。
在这里插入图片描述
TimeClient

#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(dateTimeEdit);

    getBtn = new QPushButton(tr("获取时间"));
    getBtn->setDefault(true);
    getBtn->setEnabled(false);
    quitBtn = new QPushButton(tr("退出"));
    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(enabledGetBtn()));
    connect(portLineEdit, SIGNAL(textChanged(QString)),
            this, SLOT(enabledGetBtn()));
    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();
}

TimeClient::~TimeClient()
{

}

void TimeClient::enabledGetBtn()
{
    getBtn->setEnabled(!serverNameLineEdit->text().isEmpty() &&
                       !portLabel->text().isEmpty());
}

void TimeClient::getTime()
{
    getBtn->setEnabled(false);
    time2u = 0;
    tcpSocket->abort();
    tcpSocket->connectToHost(serverNameLineEdit->text(),
                             portLineEdit->text().toInt());
}

void TimeClient::readTime()
{
    QDataStream in(tcpSocket);
    in.setVersion(QDataStream::Qt_4_3);
    if (time2u == 0)
    {
        if(tcpSocket->bytesAvailable() < (int)sizeof(uint))
            return;

        in>>time2u;
    }
    dateTimeEdit->setDateTime(QDateTime::fromTime_t(time2u));
    getBtn->setEnabled(true);
}

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

timeSever

#include "timeserver.h"
#include "timethread.h"
#include "dialog.h"
TimeServer::TimeServer(QObject *parent)
    :QTcpServer(parent)
{
    dlg = (Dialog *)parent;
}

void TimeServer::incomingConnection(int socketDescriptor)
{
    //返回的套接字描述符socketDescriptor 创建一个工作线程 TimeThread
    TimeThread *thread = new TimeThread(socketDescriptor, 0);
    /*
    将上述创建的线程结束消息函数finished()关联到槽函数slotShow()用于显示
    请求计数。次操作中,因为信号是跨线程的,所以使用了排队连接方式
    */
    connect(thread, SIGNAL(finished()), dlg, SLOT(slotShow()));
    /*
    将上述创建的线程结束消息函数finished()关联到线程自身的槽函数deleteLater()用
    于结束进程。此操作中,因为信号是在同一个线程中的,所以使用了直接连接方式,所以
    最后一个参数可以省略而使用Qt的自动连接选择方式。
    另外,由于工作线程中存在网络时间,所以不能被外界线程销毁,这里用延迟销毁函数 deleteLater()保证由工作线程自身销毁
    */
    connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()),
            Qt::DirectConnection);

    thread->start();//启动线程,工作线程的虚函数run()开始执行
}

timeThread

#include "timethread.h"
#include "timeserver.h"
#include <QDateTime>
#include <QByteArray>
#include <QDataStream>
TimeThread::TimeThread(int socketDescriptor, QObject *parent)
    :QThread(parent), socketDescriptor(socketDescriptor)
{
    
}

void TimeThread::run()
{
    QTcpSocket tcpSocket;
    //将以上创建的QTcpSocket类置以从构造函数中传入的套接字描述符,用于向客户端传回服务端当前时间
    if (!tcpSocket.setSocketDescriptor(socketDescriptor));
    {
        emit error(tcpSocket.error());
        return;
    }
    QByteArray block;
    QDataStream out(&block, QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_4_3);
    
    //如果不出错,则开始获取当前时间
    uint time2u = QDateTime::currentDateTime().toTime_t();
    out<<time2u;
    
    tcpSocket.write(block);//将获得的当前时间传回客户端
    tcpSocket.disconnectFromHost();//断开连接
    tcpSocket.waitForDisconnected();//等待返回
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值