2023年10月4日

news2024/12/26 0:14:52

服务器

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    //实例化一个服务器
    server = new QTcpServer(this);

    //此时,服务器已经成功进入监听状态,如果有客户端向服务器发来连接请求
    //那么该服务器,就会自动发射一个newConnection的信号,我们可以将该信号连接到对应槽函数中执行相关逻辑
    //由于只需要连接一次即可,所以可以将该连接放在构造函数中完成
    connect(server, &QTcpServer::newConnection, this, &Widget::newConnection_slot);
}

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

//启动服务器按钮对应的槽函数
void Widget::on_startBtn_clicked()
{
    quint16 port = ui->portEdit->text().toUInt();    //获取ui界面上的端口号

    //监听客户端的连接请求
    //函数原型:bool listen(const QHostAddress &address = QHostAddress::Any, quint16 port = 0);
    //参数1:要监听的主机地址,如果是any表示监听任意一个主机地址,也可以是特定的主机地址
    //参数2:该服务器提供的端口号,如果是0,表示由服务器自动指定,一般由程序员指定
    //返回值:成功进入监听状态,返回true,其他情况返回false
    if(!server->listen(QHostAddress::Any, port))
    {
        QMessageBox::information(this, "失败", "监听失败");
        return ;
    }else
    {
        QMessageBox::information(this, "成功", "服务器启动成功");
    }

    //此时,服务器已经成功进入监听状态,如果有客户端向服务器发来连接请求
    //那么该服务器,就会自动发射一个newConnection的信号,我们可以将该信号连接到对应槽函数中执行相关逻辑
    //由于只需要连接一次即可,所以可以将该连接放在构造函数中完成
}

//自定义处理newConnection信号的槽函数的实现
void Widget::newConnection_slot()
{
    qDebug()<<"您有新的客户端发来连接请求了";

    //获取最新连接的客户端套接字
    //函数原型:virtual QTcpSocket *nextPendingConnection();
    //参数:无
    //返回值:最新连接过来的客户端套接字的地址
    QTcpSocket *s = server->nextPendingConnection();

    //将该套接字,放入客户端链表中
    clientList.push_back(s);

    //至此,多个客户端已经跟服务器建立连接,并放入客户端容器中了
    //此时,如果有客户端向服务器发来数据,那么对应的客户端套接字就会自动发射一个readyRead信号
    //我们可以将该信号连接到自定义的槽函数中,处理相关逻辑
    connect(s, &QTcpSocket::readyRead, this, &Widget::readyRead_slot);
}

//readyRead信号对应槽函数的实现
void Widget::readyRead_slot()
{
    qDebug()<<"有新的客户端消息发来了";

    //遍历客户端链表,将无效的客户端移除
    for(int i=0; i<clientList.size(); i++)
    {
        //判断当前套接字是否是有效连接
        //函数原型: SocketState state() const;
        //参数:无
        //返回值:套接字的状态,如果是0,表示该套接字为无效连接
        if(clientList[i]->state() ==0)
        {
            //将该套接字移除客户端容器
            clientList.removeAt(i);
        }
    }

    //遍历客户端链表,判断是哪个客户端发来的数据
    for(int i=0; i<clientList.size(); i++)
    {
        //函数原型:qint64 bytesAvailable() const override;
        //功能:求当前客户端套接字中待读数据的字节数
        //参数:无
        //返回值:待读数据的字节数,如果是0,表示无数据待读
        if(clientList[i]->bytesAvailable() != 0)
        {
            //将该套接字中的数据读取出来
            QByteArray msg = clientList[i]->readAll();

            //将数据展示到ui界面
            ui->msgWidget->addItem( QString::fromLocal8Bit(msg) );

            //将接受到的数据,转发给所有客户端
            for(int j=0; j<clientList.size(); j++)
            {
                clientList[j]->write(msg);
            }
        }
    }
}


客户端

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    //给客户端指针实例化对象
    socket = new QTcpSocket(this);

    //此时,已经向服务器发送连接请求了,如果成功连接服务器,那么该客户端就会自动发射一个connected的信号
    //我们可以将该信号连接到自定义的槽函数中处理逻辑
    //由于只需要连接一次,所以将连接写在构造函数中
    connect(socket, &QTcpSocket::connected, this, &Widget::connected_slot);

    //如果服务器向客户端发来消息,那么该客户端就会自动发射一个readyRead信号
    //我们可以将该进行连接到自定义的槽函数中处理相关逻辑
    connect(socket, &QTcpSocket::readyRead, this, &Widget::readyRead_slot);

    //当成功与服务器断开连接后,该客户端会自动发射一个disconnected的信号
    //我们可以将该信号连接到自定义的槽函数中处理相关逻辑
    //由于该连接只需连接一次即可,所以放在构造函数中进行
    connect(socket, &QTcpSocket::disconnected, this, &Widget::disconnected_slot);

}

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

//连接服务器按钮对应的槽函数
void Widget::on_connectBtn_clicked()
{
    //获取ui界面上的相关信息
    userName = ui->userNameEdit->text();         //获取用户名
    QString ip = ui->ipEdit->text();            //主机地址
    quint16 port = ui->portEdit->text().toUInt();        //端口号


    //函数原型:virtual void connectToHost(const QHostAddress &address, quint16 port);
    //功能:将客户端连接到给定的服务器
    //参数1:服务器的主机地址
    //参数2:端口号
    //返回值:无
    socket->connectToHost(ip, port);

    //此时,已经向服务器发送连接请求了,如果成功连接服务器,那么该客户端就会自动发射一个connected的信号
    //我们可以将该信号连接到自定义的槽函数中处理逻辑
    //由于只需要连接一次,所以将连接写在构造函数中

}


//处理connected信号的槽函数的定义
void Widget::connected_slot()
{
    QMessageBox::information(this, "成功", "您已经成功进入聊天室");
    //向服务器发送一条数据:***:进入聊天室
    QString msg = userName +": 进入聊天室";

    socket->write(msg.toLocal8Bit());          //将数据写给服务器
}

//处理readyRead信号的槽函数的定义
void Widget::readyRead_slot()
{
    //读取套接字中的信息
    QByteArray msg = socket->readAll();

    //将数据展示到ui界面
    ui->msgWidget->addItem(QString::fromLocal8Bit(msg));
}


//发送按钮对应的槽函数
void Widget::on_sendBtn_clicked()
{
    //获取ui界面输入的内容
    QString msg =userName+ ": " + ui->msgEdit->text();

    //发送给服务器
    socket->write(msg.toLocal8Bit());

    //清空编辑框内容
    ui->msgEdit->clear();
}

//断开服务器按钮对应的槽函数
void Widget::on_disconnectBtn_clicked()
{
    //告诉大家我走了
    QString msg = userName +": 离开聊天室";
    socket->write(msg.toLocal8Bit());

    //断开连接
    //函数原型: virtual void disconnectFromHost();
    socket->disconnectFromHost();

    //当成功与服务器断开连接后,该客户端会自动发射一个disconnected的信号
    //我们可以将该信号连接到自定义的槽函数中处理相关逻辑
    //由于该连接只需连接一次即可,所以放在构造函数中进行
}

//disconnected信号对应槽函数的定义
void Widget::disconnected_slot()
{
    QMessageBox::information(this, "提示", "退出成功");
}




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

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

相关文章

Docker通过Dockerfile创建Redis、Nginx--详细过程

创建Nginx镜像 我们先创建一个目录&#xff0c;在目录里创建Dockerfile [rootdocker-3 ~]# mkdir mynginx [rootdocker-3 ~]# cd mynginx [rootdocker-3 ~]# vim Dockerfile Dockerfile的内容 FROM daocloud.io/library/centos:7 RUN buildDepsreadline-devel pcre-devel o…

Ventoy万能U盘安装系统,支持任何的操作系统安装

Ventoy万能U盘安装系统&#xff0c;支持任何的操作系统安装&#xff1a; Download . VentoyVentoy is an open source tool to create bootable USB drive for ISO files. With ventoy, you dont need to format the disk again and again, you just need to copy the iso fil…

【网络安全---ICMP报文分析】Wireshark教程----Wireshark 分析ICMP报文数据试验

一&#xff0c;试验环境搭建 1-1 试验环境示例图 1-2 环境准备 两台kali主机&#xff08;虚拟机&#xff09; kali2022 192.168.220.129/24 kali2022 192.168.220.3/27 1-2-1 网关配置&#xff1a; 编辑-------- 虚拟网路编辑器 更改设置进来以后 &#xff0c;先选择N…

基于SSM的宿舍管理系统

基于SSM的学生宿舍管理系统的设计与实现&#xff0c;前后端分离 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringSpringMVCMyBatisVue工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 【主要功能】 系统主要分学生和管理员两个角色&#xff0c;功能有…

RSA攻击:模数分解

目录 一、模数分解总览 1.1直接分解法 1.2费马分解与Pollard_rho分解 1.3公约数分解 1.4其他模数分解 二、实战特训 2.1[黑盾杯 2020]Factor 2.2[GWCTF 2019]babyRSA 2.3[LitCTF 2023]yafu (中级) 2.4[RoarCTF 2019]RSA 2.5[CISCN 2022 西南]rsa 三、总结 一、模数分解总览 …

进程调度的时机,切换与过程以及方式

1.进程调度的时机 进程调度&#xff08;低级调度〉&#xff0c;就是按照某种算法从就绪队列中选择一个进程为其分配处理机。 1.需要进行进程调度与切换的情况 1.当前运行的进程主动放弃处理机 进程正常终止运行过程中发生异常而终止进程主动请求阻塞&#xff08;如等待l/O)…

(粗糙的笔记)动态规划

动态规划算法框架&#xff1a; 问题结构分析递推关系建立自底向上计算最优方案追踪 背包问题 输入&#xff1a; n n n个商品组成的集合 O O O&#xff0c;每个商品有两个属性 v i v_i vi​和 p i p_i pi​&#xff0c;分别表示体积和价格背包容量 C C C 输出&#xff1a; …

【C语言】函数的定义、传参与调用(二)

&#x1f497;个人主页&#x1f497; ⭐个人专栏——C语言初步学习⭐ &#x1f4ab;点击关注&#x1f929;一起学习C语言&#x1f4af;&#x1f4ab; 目录 导读&#xff1a; 1. 函数的嵌套调用 1.1 什么是嵌套调用 1.2 基础实现 1.3 调用流程解析 2. 函数的链式访问 2.1 …

算法通过村第十二关-字符串|青铜笔记|隐形的王者

文章目录 前言转换成小写字母字符串转换整数总结 前言 提示&#xff1a;为别人而活着&#xff0c;其实是最简单的一种活法。 --蔡崇达《命运》 字符串本身并不是一种数据结构&#xff0c;但是由于其本身的特殊性&#xff0c;额可以产生很多特殊的算法问题。另外&#xff0c;字符…

Java之并发工具类的详细解析

3. 并发工具类 3.1 并发工具类-Hashtable Hashtable出现的原因 : 在集合类中HashMap是比较常用的集合对象&#xff0c;但是HashMap是线程不安全的(多线程环境下可能会存在问题)。为了保证数据的安全性我们可以使用Hashtable&#xff0c;但是Hashtable的效率低下。 代码实现 …

数据源报表

1.新建报表 2.新建数据集 3.维护数据源 支持的数据库还是蛮多哈 4.选择数据源表 5.编写sql 编码&#xff1a;SQL数据集的标识 注&#xff1a;避免特殊字符和_名称&#xff1a;SQL数据集的名称是否集合&#xff1a;否为单数据&#xff1b;是为多数据列表&#xff0c;如果多条数据…

MapStruct初窥门径

一、介绍 MapStruct相比于BeanUtils性能更高&#xff0c;能够实现DO&#xff0c;DTO&#xff0c;VO之间的转换&#xff0c;达到解耦合的目的 二、使用前提 添加依赖 <dependency><groupId>org.mapstruct</groupId><artifactId>mapstruct</artifa…

第八章 Linux文件系统权限

目录 8.1 文件的一般权限 1.修改文件或目录的权限---chmod命令 2.对于文件和目录&#xff0c;r&#xff0c;w&#xff0c;x有不同的作用&#xff1a; 3.修改文件或目录的所属主和组---chown,chgrp 8.2 文件和目录的特殊权限 三种通过字符描述文件权限 8.3 ACL 权限 1.A…

基于Java的药店管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…

1500*A. Boredom(DP)

Problem - 455A - Codeforces Boredom - 洛谷 解析&#xff1a; 首先统计每个数的个数&#xff0c;并且统计出最大值mx。 问题转换为&#xff0c;从1-mx 中选择任意个数字&#xff0c;使其都不相邻&#xff0c;求最大的总和。 开始没有思路&#xff0c;以为直接选取偶数位和奇…

项目进展(七)-焊接ADS1285及其外围电路,学习芯片的SPI部分

一、焊接芯片及其外围电路 总体焊接过程没有出现什么大问题&#xff0c;也算顺利&#xff0c;下一步主要是根据SPI来编写代码&#xff0c;配置该芯片。 焊接之后的PCB如下(手工焊接&#xff0c;比较丑陋&#xff0c;哈哈哈哈) 之后测试了4.096V参考电压和晶振输出&#xff0c…

CART算法解密:从原理到Python实现

目录 一、简介CART算法的背景例子&#xff1a;医疗诊断 应用场景例子&#xff1a;金融风控 定义与组成例子&#xff1a;电子邮件分类 二、决策树基础什么是决策树例子&#xff1a;天气预测 如何构建简单的决策树例子&#xff1a;动物分类 决策树算法的类型例子&#xff1a;垃圾…

长时序栅格数据缺失值插补

长时序栅格数据经常会出现一些缺失值&#xff0c;会对后续的分析造成很大的不便。这便需要利用一些插值算法对这些缺失数据进行填补&#xff0c;奇异谱分析&#xff08;SSA&#xff09;便是常用的一种插值方法。更多内容可见公众号GeodataAnalysis。 简介 在时间序列分析中&a…

处理机调度的概念,层次联系以及七状态模型

1.基本概念 当有一堆任务要处理&#xff0c;但由于资源有限&#xff0c;这些事情没法同时处理。 这就需要确定某种规则来决定处理这些任务的顺序&#xff0c;这就是“调度”研究的问题。 2. 三个层次 1.高级调度&#xff08;作业调度&#xff09; 高级调度&#xff08;作业…

websocket逆向【python实现websocket拦截】

python实现websocket拦截 前言一、拦截的优缺点优点:缺点:二、实现方法1.环境配置2.代码三、总结前言 开发者工具F12,筛选ws后,websocket的消息是这样显示的,如何获取这里面的消息呢? 以下是本篇文章正文内容 一、拦截的优缺点 主要讲解一下websocket拦截的实现,现在…