多线程服务器

news2024/11/25 16:47:48

设计一个客户端从服务器端获取时间的程序:

服务器端使用多线程的方式,当有客户端请求到达时,服务器将启动一个新线程为它返回当前的时间,服务完后线程自动销毁,服务器端会显示连接的次数。

客户端比较简单,先搭建客户端。 

客户端的搭建 :

创建一个项目:名为:TCP_Client

pro文件添加

QT +=netwowork

ui界面添加以下控件:

dialog.h文件:

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include<QTcpSocket>
#include<QAbstractSocket>
QT_BEGIN_NAMESPACE
namespace Ui { class Dialog; }
QT_END_NAMESPACE

class Dialog : public QDialog
{
    Q_OBJECT

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

private slots:
    void on_pushButton_clicked();

    void on_pushButton_2_clicked();
    void  enableBth();//设置是否可以点击获取时间
    void error_string(QAbstractSocket::SocketError);//输出错误信息

private:
    Ui::Dialog *ui;
    QTcpSocket *socket;//套接字
    uint timer;//时间
};
#endif // DIALOG_H

dialog.cpp文件:

#include "dialog.h"
#include "ui_dialog.h"

#include <QDateTime>
#include<QMessageBox>
Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
    , ui(new Ui::Dialog)
{
    ui->setupUi(this);
    setWindowTitle("客户端");
    socket=new QTcpSocket(this);
    connect(ui->lineEdit,&QLineEdit::textChanged,this,&Dialog::enableBth);//当服务器名输入框内容改变时,执行该函数
    connect(ui->lineEdit_2,&QLineEdit::textChanged,this,&Dialog::enableBth);//当端口输入框内容改变时,执行该函数
    connect(socket,&QTcpSocket::readyRead,[=]()//当有可读数据时
    {
        QDataStream in(socket);//创建流
        in.setVersion(QDataStream::Qt_5_9);
        if(timer==0)
        {
            if(socket->bytesAvailable()<(int)sizeof(uint))//如果过数据太小,不接收
            {
                return;
            }
            in>>timer;//读取数据
        }
        ui->dateTimeEdit->setDateTime(QDateTime::fromTime_t(timer));//显示获取的时间
        ui->pushButton->setEnabled(true);//将获取时间的按键设为可点击
    });
//当触发error信号时,执行    connect(socket,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(error_string(QAbstractSocket::SocketError)));
    ui->lineEdit_2->setFocus();//获取焦点
}

Dialog::~Dialog()
{
    delete ui;
}


void Dialog::on_pushButton_clicked()//获取时间
{
    ui->lineEdit->setEnabled(false);
    timer=0;
    socket->abort();//断开已有连接
    socket->connectToHost(ui->lineEdit->text(),ui->lineEdit_2->text().toInt());//创建连接
}

void Dialog::on_pushButton_2_clicked()//退出
{
    close();//关闭界面
}
void Dialog::enableBth()
{
    ui->pushButton->setEnabled(!ui->lineEdit->text().isEmpty()&&!ui->lineEdit_2->text().isEmpty());//端口和主机不能为空
}
void Dialog::error_string(QAbstractSocket::SocketError socketerror)//输出错误信息
{
    switch(socketerror)
    {
    case QAbstractSocket::RemoteHostClosedError:
        break;
    case QAbstractSocket::HostNotFoundError:
        QMessageBox::information(this,"错误信息",tr("主机不可达"));
        break;
    case QAbstractSocket::ConnectionRefusedError:
        QMessageBox::information(this,"错误信息",tr("连接被拒绝"));
    default:
        QMessageBox::information(this,"错误信息",tr("%1").arg(socket->errorString()));//获取错误信息
    }
    ui->pushButton->setEnabled(true);

}

服务器的搭建:

难点在于如何搭建多线程服务器。

创建一个新项目:Server_thread

服务器的搭建需要创建3个类:

  • 主界面类:接受和显示连接次数的类:tcp_server
  • 线程类:用来通过套接字发送时间的类:timethread类
  • 服务器类:用来建立连接的类:timeserver

搭建的关键:服务器有连接时,使用线程进行执行,(所以要重写有连接时的函数)线程执行完发送信号给主类,显示数据。

每个类的搭建过程:

主页面类:

 服务器类:

 线程类:

 

目录: 

 

1.创建项目时已经创建了tcp_server类 (主界面)

pro文件中添加:

QT  +=network

2.创建 线程类:继承自QThread

timeThread.h文件

#ifndef TIMETHREAD_H
#define TIMETHREAD_H

#include <QThread>
#include<QTcpServer>
#include<QTcpSocket>
#include<QDataStream>
class timeThread : public QThread//继承自QThread
{
    Q_OBJECT
public:
    explicit timeThread(qintptr socketDescriptor,QObject *parent=nullptr);//初始时时需要传入套接字描述
    void run();//重写run函数

signals:
    void error(QTcpSocket::SocketError socketError);//出错信号


private:
      qintptr socketDescriptor;  //套接字描述

};

#endif // TIMETHREAD_H

 timethread.cpp文件

#include "timethread.h"

#include <QDateTime>

timeThread::timeThread(qintptr socketDescriptor,QObject *parent)
    : QThread(parent),socketDescriptor(socketDescriptor)//初始化套接字描述
{

}
void timeThread::run()//重写run函数,服务器有连接使,创建套接字来传输数据
{
    QTcpSocket tcpSocker;
    if(!tcpSocker.setSocketDescriptor(socketDescriptor))
    {
        emit error(tcpSocker.error());//触发错误信号
        return;
    }
    QByteArray block;
    QDataStream out(&block,QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_5_9);//设置版本好
    uint tim2u=QDateTime::currentDateTime().toTime_t();//获取时间,转化为标准格式
    out<<tim2u;
    tcpSocker.write(block);//传回客户端
    tcpSocker.disconnectFromHost();//断开连接
    tcpSocker.waitForDisconnected();//等待返回

}

3.创建服务器类:timeserver 继承自QTcpServer

timeserver.h文件:

#ifndef TCP_SERVER_H
#define TCP_SERVER_H
#include "timeserver.h"
#include <QDialog>
#include<QTcpServer>
#include<QTcpSocket>
#include<QLabel>
#include<QPushButton>
QT_BEGIN_NAMESPACE
namespace Ui { class TCP_server; }
QT_END_NAMESPACE
class timeserver;
class TCP_server : public QDialog
{
    Q_OBJECT
public:
    TCP_server(QWidget *parent = nullptr);
    ~TCP_server();
private slots:
    void slotShow();//用来显示界面上的请求次数

private:
    Ui::TCP_server *ui;
    QLabel *lab1;//显示端口号
    QLabel *lab2;//显示已连接的个数
    QPushButton *pbt;//退出按键
    timeserver *server;//服务器端
    int count;//统计个数

};
#endif // TCP_SERVER_H

timeserver.cpp文件:

#include "timeserver.h"
#include<timethread.h>
timeserver::timeserver(QObject *parent) : QTcpServer(parent)
{
    tcp_Dia=(TCP_server *)parent;//获取创建这个timeserver对象的父类
}
void timeserver::incomingConnection(qintptr socketDescriptor)
{
    timeThread *thread=new timeThread(socketDescriptor,0);//创建一个工作线程
    connect(thread,SIGNAL(finished()),tcp_Dia,SLOT(slotShow()),Qt::QueuedConnection);//使用排队连接方式
    connect(thread,SIGNAL(finished()),thread,SLOT(deleteLater()),Qt::DirectConnection);//当线程结束时,销毁线程
    thread->start();//开启线程
}

4.Tcp_Server(主界面)

ui界面中添加以下控件: QLabel    QLabel   QPushbutton

 

tcp_server.h文件:

#ifndef TCP_SERVER_H
#define TCP_SERVER_H
#include "timeserver.h"
#include <QDialog>
#include<QTcpServer>
#include<QTcpSocket>
#include<QLabel>
#include<QPushButton>
QT_BEGIN_NAMESPACE
namespace Ui { class TCP_server; }
QT_END_NAMESPACE

class timeserver;//服务器端的前置声明
class TCP_server : public QDialog
{
    Q_OBJECT


public:
    TCP_server(QWidget *parent = nullptr);
    ~TCP_server();
private slots:
    void slotShow();//用来显示界面上的请求次数

    void on_pushButton_clicked();//退出

private:
    Ui::TCP_server *ui;
    timeserver *server;//服务器端
    int count;//统计个数

};
#endif // TCP_SERVER_H

tcp_server.cpp文件:

#include "tcp_server.h"
#include "ui_tcp_server.h"
#include <QMessageBox>
#include<QHBoxLayout>
#include<QVBoxLayout>
TCP_server::TCP_server(QWidget *parent)
    : QDialog(parent)
    , ui(new Ui::TCP_server)
{
    ui->setupUi(this);
    //控件初始化
    setWindowTitle(tr("多线程时间服务器"));
    lab1=new QLabel("服务器端口");
    lab2=new QLabel;
    pbt=new QPushButton(tr("退出"));
    QHBoxLayout *hlay=new QHBoxLayout;
    hlay->addStretch(1);
    hlay->addWidget(pbt);
    hlay->addStretch(1);
    QVBoxLayout *vlay=new QVBoxLayout(this);
    vlay->addWidget(lab1);
    vlay->addWidget(lab2);
    vlay->addLayout(hlay);


    connect(pbt,&QPushButton::clicked,this,&TCP_server::close);//点击退出关闭窗口
    count=0;
    server=new timeserver(this);
    if(!server->listen())
    {
        QMessageBox::information(this,"提示信息",tr("无法启动服务器:%1").arg(server->errorString()));

        return;
    }
    lab1->setText(tr("服务器端口:%1").arg(server->serverPort()));
}

TCP_server::~TCP_server()
{
    delete ui;
}
void TCP_server::slotShow()//用来显示界面上的请求次数
{
    lab2->setText(tr("第%1次请求完毕").arg(++count));
}

运行效果:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/346126.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MySQL安装手册

文章目录一、系统环境二、检查是否已安装三、安装步骤1、yum安装1.1、更新yum1.2、使用wget下载mysql yum源&#xff1a;1.3、添加 mysql yum 源:1.4、安装 yum 工具 yum-utils :1.5、查看可用的 mysql :1.6、查看所有的 mysql 版本1.7、使用指定版本MySQL1.8、查看当前启用的M…

Netty源码解读-server端(一)

一、回顾NIO中的server 下面是我在学习nio时&#xff0c;写的selctor版本的服务端&#xff0c;具体代码如下&#xff1a; public static void nioSelectorServer() throws Exception{//1。创建SelectorSelector selector Selector.open();ServerSocketChannel ssc ServerSo…

c++ bind 函数讲解

1.bind 函数的使用详解 可以将bind函数看作一个通用的函数适配器&#xff0c;它接受一个可调用对象&#xff0c;生成一个新的可调用对象来“适应”原对象的参数列表。 调用bind的一般形式&#xff1a;auto newCallable bind(callable,arg_list); 其中&#xff0c;newCallab…

从零实现深度学习框架——再探多层双向RNN的实现

来源&#xff1a;投稿 作者&#xff1a;175 编辑&#xff1a;学姐 往期内容&#xff1a; 从零实现深度学习框架1&#xff1a;RNN从理论到实战&#xff08;理论篇&#xff09; 从零实现深度学习框架2&#xff1a;RNN从理论到实战&#xff08;实战篇&#xff09; 从零实现深度…

【Vue3】首页主体-面板组件封装

首页主体-面板组件封装 新鲜好物、人气推荐俩个模块的布局结构上非常类似&#xff0c;我们可以抽离出一个通用的面板组件来进行复用 目标&#xff1a;封装一个通用的面板组件 思路分析 图中标出的四个部分都是可能会发生变化的&#xff0c;需要我们定义为可配置主标题和副标题…

您可以使用 21 个很棒的搜索引擎来代替 Google

在过去的 20 年里&#xff0c;Google 一直是大多数人用于日常搜索、产品研究和了解最新消息的搜索引擎。凭借其长期的统治地位和大部分市场份额&#xff0c;很难说任何搜索引擎都能提供比谷歌更好的结果。由于这种市场主导地位&#xff0c;谷歌也一直是SEO和营销专业人士关注的…

随笔-老子不想牺牲了

18年来到这个项目组&#xff0c;当时只有8个人&#xff0c;包括经常不在的架构师和经理。当时的工位在西区1栋A座&#xff0c;办公桌很宽敞。随着项目的发展&#xff0c;入职的人越来越多&#xff0c;项目的工位也是几经搬迁。基本上每次搬迁时&#xff0c;我的工位都是挑剩下的…

Allegro如何实现同一个屏幕界面分屏显示操作指导

Allegro如何实现同一个屏幕界面分屏显示操作指导 在做PCB设计的时候,会需要分屏显示,比如一边是放大的视图,另外一边是缩小的视图,Allegro支持同一个屏幕界面下进行分屏显示,如下图 而且会实时同步起来 如何分屏,具体操作如下 点击View

(python)降低图像质量

降低数字图像质量(python实现) 目录 降低数字图像质量(python实现)一、分别采用五种不同的方式来降低图像的质量1. 给图像添加椒盐噪声2. 给图像添加高斯噪声3. 对图像进行高斯模糊4. 对图像进行运动模糊5. 对图像进行插值下采样二、实现代码一、分别采用五种不同的方式来降…

操作系统(六)磁盘调度算法与优化

操作系统&#xff08;六&#xff09;磁盘调度算法与优化 一、磁盘调度算法 时间指标 寻找时间&#xff1a;在读/写数据前&#xff0c;将磁头移动到指定磁道需要的时间延迟时间&#xff1a;通过旋转盘面&#xff0c;将磁头定位到目标扇区所需的时间传输时间&#xff1a;从磁盘…

Leetcode.1124 表现良好的最长时间段

题目链接 Leetcode.1124 表现良好的最长时间段 Rating &#xff1a; 1908 题目描述 我们认为当员工一天中的工作小时数大于 8 小时的时候&#xff0c;那么这一天就是「劳累的一天」。 所谓「表现良好的时间段」&#xff0c;意味在这段时间内&#xff0c;「劳累的天数」是严格…

argocd 调研

Argo CD 是基于 Kubernetes 的声明式&#xff0c; GitOps 持续交付工具。GitOps AgentGitOps IaC Git CI/CD&#xff0c;即基于 IaC 的版本化 CI/CD。它的核心是使用 Git 仓库来管理基础设施和应用的配置&#xff0c;并且以 Git 仓库作为基础设施和应用的单一事实来源。Git …

Windows 11 办公实用效率小技巧总结(持续更新)

Win11 办公实用效率小技巧总结:1. 虚拟桌面2. 拖拽任务窗口转移到不同虚拟桌面3. 自定义多网页名称4. Focus专注组件5. 多选项分屏6. 抖一抖最小化1. 虚拟桌面 虽然过去只有 Linux&#xff0c; Mac 系统中有虚拟桌面&#xff0c;而且在win10 中也实现了这个功能&#xff0c;但…

Springboot835学生成绩分析系统--java

开发语言&#xff1a;Java 框架&#xff1a;Springboot 技术&#xff1a;JSP JDK版本&#xff1a;JDK1.8 目 录 1 绪 论 5 1.1课题背景 5 1.2 课题研究的意义 5 1.3 系统实现的功能 5 1.4 课题研究现状 5 2系统相关技术 7 2.1 Java技术 7 2.2 B/S架构 7 2.3 MySQL 介绍 7 2.4My…

zabbix邮件报警配置

在Zabbix服务端设置邮件报警&#xff0c;当被监控主机宕机或者达到触发器预设值时&#xff0c;会自动发送报警邮件到指定邮箱。 邮件服务可以使用系统自带的邮件服务来发送邮件或者使用其他邮件服务调用第三方邮件来发送警告邮件。 一、开启发件服务器SMTP功能 这里发送邮件的…

初始C++(四):内联函数

文章目录一.内联函数概念二.内联函数用法三.内联函数的特性四.内联函数和宏一.内联函数概念 以inline修饰的函数叫做内联函数&#xff0c;编译时C编译器会在调用内联函数的地方展开&#xff0c;没有函数调用建立栈帧的开销&#xff0c;内联函数提升程序运行的效率。 二.内联函…

SpringBoot环境-MySQL主从复制,读写分离的实现

目录 概述 环境 主从复制 读写分离 概述 记录在MySQL数据库中主从复制以及SpringBoot环境操作MySQL数据库读写分离的实现步骤。 背景 &#xff1a;因为我们在对数据库进行操作时&#xff0c;如果读写操作都由一台数据库承担的话压力会比较大&#xff0c;为了减轻数据库压力&…

【Linux】rsyslog日志服务(配置,测试、日志转储)

一、rsyslog简介 Rsyslog的全称是 rocket-fast system for log ,可用于接受来自各种来源的输入&#xff0c;转换 它们&#xff0c;并将结果输出到不同的目的地。 它提供了高性能、强大的安全功能和模块化设计。虽然rsyslog最初是一个常规的系 统日志&#xff0c;但它已经发展成…

H5APP开发封装流程

1.利用H5写想要的功能 2.打包APP 3.手机安装 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0, maximum-scale1.0, user-sca…

【基础】Flink -- Time and Window

Flink -- Time and WindowFlink 时间语义水位线 Watermark水位线的概念有序流中的水位线乱序流中的水位线水位线的特性水位线的基本使用水位线生成策略内置水位线生成器自定义水位线策略在自定义数据源中发送水位线窗口 Window窗口的基本概述窗口的基本概念窗口的分类窗口的 AP…