tcp的聊天室

注意:要加库文件,服务端客户端都要加 network

客户端的头文件

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTcpSocket>//客户端类
#include <QMessageBox>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

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

private slots:

    void on_sendbtn_clicked();

    void on_disconnectbtn_clicked();
    void on_connectbtn_clicked();
public slots:
    void connected_slot();
    void readyRead_slot();
    void disconnected_slot();

private:
    Ui::Widget *ui;
    //定义客户端指针
    QTcpSocket *socket;

    //定义存储用户名
    QString username;
};
#endif // WIDGET_H

客户端主函数

#include "widget.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}

 客户端构造函数

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

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    //初始化界面
    //设置按钮不可以状态
    ui->msgEdit->setEnabled(false);
    ui->sendbtn->setEnabled(false);
    ui->disconnectbtn->setEnabled(false);

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

    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界面上的ip和端口号
    QString ip=ui->ipEdit->text();
    quint16 port =ui->portEdit->text().toUInt();
    //将客户连接到服务器
    //参数1:主机地址
    //参数2:端口号
    socket->connectToHost(ip,port);

    //如果成功连接服务器,那么客户端将发送一个conneted信号
    //我们就可以将该信号连接到自定义的槽函数中处理逻辑代码,由于只需要连接一次,所有我们在构造函数中写连接

}


void Widget::connected_slot()
{
    QMessageBox::information(this,"","连接服务器成!");

    //告诉服务器,用户上线
    username =ui->userEdit->text();

    QString msg=username+": 进入聊天室";

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

    //将ui界面上的组件进行相关设置

    //可用状态
    ui->msgEdit->setEnabled(true);
    ui->sendbtn->setEnabled(true);
    ui->disconnectbtn->setEnabled(true);

    //不可以状态
    ui->userEdit->setEnabled(false);
    ui->ipEdit->setEnabled(false);
    ui->portEdit->setEnabled(false);
    ui->connectbtn->setEnabled(false);

    //此时客户端和服务器已经建立连接,如果服务器发来数据,那么客户端就会自动发射 一个readyRead()信号
    //我们可以将该信号连接到自定义的槽函数中,读取服务器端的数据,又由只需要连接一次,在构造函数写连接

}

void Widget::readyRead_slot()
{
    //将服务器端的数据读取出来
    QByteArray msg =socket->readAll();

    //将数据放入ui界面上
    ui->msgWidget->addItem(QString::fromLocal8Bit(msg));
}


//disconnected信号对应的槽函数的实现
void Widget::disconnected_slot()
{
    QMessageBox::information(this,"","断开服务器成功");
    ui->msgEdit->setEnabled(false);
    ui->sendbtn->setEnabled(false);
    ui->disconnectbtn->setEnabled(false);

    ui->userEdit->setEnabled(true);
    ui->ipEdit->setEnabled(true);
    ui->portEdit->setEnabled(true);
    ui->connectbtn->setEnabled(true);

}

//发送按钮对应的槽函数
void Widget::on_sendbtn_clicked()
{
    //获取ui界面上的数据
    QString msg=ui->msgEdit->text();

    //整合信息
    msg=username+":"+msg;

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

    //清空发送框里的内容
    ui->msgEdit->clear();
}

//端口服务器按钮的槽函数处理
void Widget::on_disconnectbtn_clicked()
{
    //告诉大家我走了
    QString msg =username+":离开聊天室";

    //信息发送给服务器
    socket->disconnectFromHost();

    //如果成功与服务器断开连接,那么该客户端就会自动发送一个disconnected信号
    //我们就可以将该信号连接到自定义函数中,处理逻辑代码,由于只要连接一次,所有在构造函数中连接
}

客户端ui界面

 

服务端头文件

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTcpServer>
#include <QList> //链表容器
#include <QTcpSocket> //客户端的类
#include <QMessageBox> //消息对话框类

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

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

private slots:
    void on_staetBtn_clicked();
    void newConnection_solt(); //newconnection信号对应的槽函数
    void readyRead_slot();

private:
    Ui::Widget *ui;
    //定义服务器指针
    QTcpServer *server;


    //定义客户端容器
    QList<QTcpSocket *> socketList;

};
#endif // WIDGET_H

服务端主函数

#include "widget.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}

服务的构造函数

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

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

    //给服务器指针实例化空间
    server =new QTcpServer(this);


}

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

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

   //将服务器设置监听状态
   //函数原型:bool
   //参数1:主机地址 可以是任意
    //参数2:端口号
    if(server->listen(QHostAddress::Any,port))
    {
        QMessageBox::information(this,"","启动服务器成功!");
    }
    else
    {
        QMessageBox::information(this,"","启动服务器失败!");
    }

    //此时说明服务器已经进入监听状态,如果有客户端发来连接请求,那么服务器端就会自动发射newconnection
    //将该信号连接到自定义的槽函数中,获取客户端的套接字
    connect(server,&QTcpServer::newConnection,this,&Widget::newConnection_solt);
}

//newConnection信号对应槽函数处理
void Widget::newConnection_solt()
{
    qDebug() <<"有新的用户连接" ;

    //获取最新连接的客户端套接字
    //函数原型:virtual QTcpSocket *nextPendingConnection();
    //返回值:是客户端套接字的指针
    QTcpSocket *s =server->nextPendingConnection();

    //将套接字放入容器中
    socketList.push_back(s);

    //程序运行至此,说明服务端和客户端已经建立起联系,如果客户端发来数据,那么客户端就会自动发射readyrRead()信号
    //我们就可以将信号连接自定义的槽函数中,读取客户端的数据
    connect(s,&QTcpSocket::readyRead,this,&Widget::readyRead_slot);


}
//readyRead信号对应槽函数声明
void Widget::readyRead_slot()
{
    //移除无效客户端
    //count :在容器中的所有元素个数
    for(int i=0;i<socketList.count();i++)
    {
        //函数原型:socketstate state() const
        if(socketList.at(i)->state()==0)
        {
            //移除
            socketList.removeAt(i);//将下表为i的 客户端移除

        }
    }

    //遍历有效客户端,寻找哪个客户端有数据待读
    for (int i=0;i<socketList.count();i++)
    {
        //函数原型:
        //判断是否有数据
        if(socketList.at(i)->bytesAvailable()!=0)
        {
            //读取套接字中的数据
            QByteArray msg = socketList.at(i)->readAll();

            //将数据放在ui界面上
            ui->msgWidget->addItem(QString::fromLocal8Bit(msg));

            //将数据广播给(发送)给所有客户端
            for(int j=0;j<socketList.count();j++)
            {
                //将数据写入到套接字中
                socketList.at(j)->write(msg);
            }

        }
    }
}

服务端ui界面

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Ubuntu 设置共享文件夹

一、在Windows中建立一个英文的文件夹 注意&#xff1a;新建文件夹的名称一定要是英文的&#xff0c;不能出现中文的路径&#xff08;可能出现问题&#xff09; 二、在VMware中添加共享文件 3: VMware安装VMware Tools 一般安装成功桌面上会显示这个安装包&#xff0c;&…

RV32/64 特权架构

machine mode: 运行最可信的代码;supervisor mode:为 Linux&#xff0c;FreeBSD 和 Windows 等操作系统提供支持;user mode:权限最低&#xff0c;应用程序的代码在此模式下运行&#xff1b; 这两种新模式都比user mode有着更高的权限&#xff0c;有更多权限的模式通常可以使用…

深度学习中的13种概率分布

1 概率分布概述 共轭意味着它有共轭分布的关系。 在贝叶斯概率论中&#xff0c;如果后验分布 p&#xff08;θx&#xff09;与先验概率分布 p&#xff08;θ&#xff09;在同一概率分布族中&#xff0c;则先验和后验称为共轭分布&#xff0c;先验称为似然函数的共轭先验。 多…

Python实现多种图像锐化方法:拉普拉斯算子和Sobel算子

Python实现多种图像锐化方法&#xff1a;拉普拉斯算子和Sobel算子 图像和视频逐渐成为人们生活中信息获取的重要来源&#xff0c;而图像和视频在传输过程中有很多因素可能造成图像模糊&#xff0c;比如不正确的聚焦会产生离焦模糊&#xff0c;景物和照相机的相对运动会造成运动…

C# 编写Windows服务程序

1.什么是windows服务&#xff1f; Microsoft Windows 服务&#xff08;即&#xff0c;以前的 NT 服务&#xff09;使您能够创建在它们自己的 Windows 会话中可长时间运行的可执行应用程序。这些服务可以在计算机启动时自动启动&#xff0c;可以暂停和重新启动而且不显示任何用…

基于自动化脚本批量上传依赖到nexus内网私服

前言 因为某些原因某些企业希望私服是不能连接外网的&#xff0c;所以需要某些开源依赖需要我们手动导入到nexus中&#xff0c;尽管nexus为我们提供了web页面。但是一个个手动导入显然是一个庞大的工程。 对此我们就不妨基于脚本的方式实现这一过程。 预期效果 笔者本地仓库…

IDEA之设置主题风格为eclipse风格

设置IDEA的主题风格为eclipse风格&#xff0c;步骤如下: 1.选择File->Settings 2.选择 Plugins 3.搜索 eclipse theme&#xff0c;注意是红框里的&#xff0c;点击 install 下载后就会自动设置这个主题 4.你也可以去修改主题&#xff0c;选择 Appearance&#xff0c;设置th…

deepstream-python安装

​ 安装deepstream-docker 在这边文章中deepstream-docker详细介绍了如何在Ubuntu下安装deepstream-docker&#xff0c;安装完成之后&#xff0c;为了快速入门deepstream&#xff0c;我们可以安装deepstream-python库&#xff0c;通过阅读相应的例子来快速搭建一个应用。 安…

认识loader和plugin

在 webpack 中&#xff0c;专注于处理 webpack 在编译过程中的某个特定的任务的功能模块&#xff0c;可以称为插件。它和 loader 有以下区别&#xff1a; 1loader 是一个转换器&#xff0c;将 A 文件进行编译成 B 文件&#xff0c;比如&#xff1a;将 A.less 转换为 A.css&…

IDEA之设置项目包的结构层级为eclipse默认样式

idea默认项目包的结构层级如下: 想修改成eclipse默认的那种样式&#xff0c;设置步骤如下: 1.点击下图中红框图标进行设置 2.选择 Tree Appearance&#xff0c;取消勾选 Compact Middle Packages 3.勾选红框里的两个选项&#xff0c;Flatten Packages 和 Hide Empty Middle Pa…

HTML插入视频和音频(详解)

&#x1f4cd;文章目录&#x1f4cd; &#x1f9c0;一&#xff0c;简介&#x1f9c0;二&#xff0c;视频(video)&#x1f367;1&#xff0c;普通的视频插入&#x1f367;2&#xff0c;在html5中嵌入视频网站视频 &#x1f9c0;三&#xff0c;音频(audio) &#x1f9c0;一&#…

50mA、24V、超低 IQ、低压降稳压器

一、Description The TPS715 low-dropout (LDO) voltage regulators offer the benefits of high input voltage, low-dropout voltage, low-power operation, and miniaturized packaging. The devices, which operate over an input range of 2.5 V to 24 V, are stable wit…

Wordle 游戏实现 - 使用 C++ Qt

标题&#xff1a;Wordle 游戏实现 - 使用 C Qt 摘要&#xff1a; Wordle 是一款文字猜词游戏&#xff0c;玩家需要根据给定的单词猜出正确的答案&#xff0c;并在限定的次数内完成。本文介绍了使用 C 和 Qt 框架实现 Wordle 游戏的基本思路和部分代码示例。 引言&#xff1a;…

jmeter简单压测kafka

前言 这也是一个笔记&#xff0c;就是计划用jmeter做性能测试&#xff0c;但是这里是只要将数据放到kafka的topic里&#xff0c;后面查看下游业务处理能力。 一、方案 因为只要实现数据放到kafka&#xff0c;参考了下博友的方案&#xff0c;可行。 二、方案验证 详细过程就不…

CNN 卷积神经网络之 DenseNet 网络的分类统一项目(包含自定义数据集的获取)

1. DenseNet 网络介绍 本章实现的项目是DenseNet 网络对花数据集的五分类&#xff0c;下载链接&#xff1a; 基于迁移学习的 DenseNet 图像分类项目 DenseNet 网络是在 ResNet 网络上的改进&#xff0c;大概的网络结构如下&#xff1a; 1.1 卷积的简单介绍 图像识别任务主要…

计算机速成课Crash Course - 10. 早期的编程方式

今天继续计算机速成课Crash Course的系列讲解。 更多技术文章&#xff0c;关注公众号 “摸鱼IT” 锁定 -上午11点 - &#xff0c;感谢大家关注、转发、点赞&#xff01; 10. 早期的编程方式 前几集我们把重点放在计算机的原理&#xff0c;怎么从内存读写数据&#xff0c;执行…

js基础:函数、对象、WebAPIs-DOM

一、函数和对象 1、函数概述 &#x1f916;chatgpt&#xff1a;什么是函数&#xff1f;为什么要有函数&#xff1f; 函数是一种可重复使用的代码块&#xff0c;它们可以接受输入&#xff08;参数&#xff09;、执行特定的任务&#xff0c;并返回结果。 JavaScript中函数是非常…

鸿蒙OS应用开发之按钮组件(2)

前面学习了简单的按钮添加到程序里,并且使用了简单的布局排列来放置。其实按钮还有很多种形式,会在不同的场合来使用。 默认的按钮外形,跟前面例子的程序是一样的: 包含着图片的按钮: 不同外形的按钮:

Python编程进阶:轻松掌握多线程和多进程

大家好&#xff0c;今天我们将讨论如何利用Python执行多线程和多进程任务。它们提供了在单个进程或多个进程之间执行并发操作的方法&#xff0c;并行和并发执行可以提高系统的速度和效率。在讨论多线程和多进程的基础知识之后&#xff0c;我们还将讨论使用Python库实现它们的实…

利用poi实现将数据库表字段信息导出到word中

研发文档对于开发人员来说都不陌生了&#xff0c;而研发文档里重要的一部分就是表结构设计&#xff0c;需要我们在word建个表格把我们数据库中的表字段信息填进去&#xff0c;表多的话靠我们手动去填非常累人&#xff01;&#xff01;&#xff01; 因此作为开发人员可不可以写…