QTday05(TCP的服务端客户端通信)

实现聊天室功能

服务端代码:

pro文件需要导入 network

头文件:

cpp 复制代码
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTcpServer>//服务端
#include <QTcpSocket>//客户端
#include <QList>
#include <QMessageBox>
#include <QDebug>

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_startBtn_clicked();
public slots:
    void newConnectSlot();//建立连接的槽函数
    void readyReadSlot();//接收消息的槽函数

private:
    Ui::Widget *ui;

    //实例化服务器对象
    QTcpServer *server;
    //创建存放客户端信息的容器
    QList<QTcpSocket *> socketList;
};
#endif // WIDGET_H

widget.cpp

cpp 复制代码
#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_startBtn_clicked()
{
    //监听任意ip的指定端口
    bool listen_res=server->listen(QHostAddress::Any,ui->portLine->text().toUInt());
    if(listen_res){
        //监听成功
        QMessageBox::information(this,"提示","设置监听成功",QMessageBox::Ok);

    }else{
        //监听失败
        QMessageBox::information(this,"提示","设置监听失败",QMessageBox::Ok);
        return;
    }
    //等待连接
    connect(server,&QTcpServer::newConnection,this,&Widget::newConnectSlot);
}

void Widget::newConnectSlot()
{
    //接收到newConnect信号之后的槽函数,处理接下来的操作

    //获取客户端的套接字,加入容器
    QTcpSocket *s=server->nextPendingConnection();
    socketList.push_back(s);
    qDebug() << "有新客户连接" << s->peerName() << ";" << s->peerAddress().toString() << ":" << QString::number(s->peerPort()) <<endl;
    //此时如果客户端向服务器发送数据,客户端会发送一个readyRead信号
    connect(s,&QTcpSocket::readyRead,this,&Widget::readyReadSlot);
}

void Widget::readyReadSlot()
{
    //客户端有数据发送,触发改槽函数
    //遍历容器,移除无效客户端,接收有效客户端消息
    for (int i=0;i<socketList.count();i++) {
        //如果是非链接状态就移除
        if(socketList.at(i)->state()==QAbstractSocket::UnconnectedState){
            socketList.removeAt(i);
        }
    }
    for (int i=0;i<socketList.count();i++) {
        //如果有字节,就读取并放到ui界面
        if(socketList.at(i)->bytesAvailable()){
            QByteArray msg=socketList.at(i)->readAll();
            QString msgInfo=socketList.at(i)->peerAddress().toString()+":"+QString::number(socketList.at(i)->peerPort())+":"+QString::fromLocal8Bit(msg);
            ui->listWidget->addItem(msgInfo);
            for (int j=0;j<socketList.count();j++) {
                socketList.at(j)->write(msg);
            }
        }
    }
}

ui:

客户端代码:

头文件

cpp 复制代码
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QtDebug>
#include <QMessageBox>
#include <QTcpSocket>

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_connnectBtn_clicked();

    void on_disconnectBtn_clicked();

    void on_sendBtn_clicked();

public slots:
    void connnectedSlot();
    void readyReadSlot();
    void disconnectedSlot();

private:
    Ui::Widget *ui;

    //实例化客户端
    QTcpSocket *socket;
    //定义全局变量存储用户名
    QString username;
};
#endif // WIDGET_H

widget.cpp

cpp 复制代码
#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    //实例化客户端
    socket=new QTcpSocket(this);
    //将发送和断开连接 的按钮默认设置不可用
    ui->sendBtn->setDisabled(true);
    ui->disconnectBtn->setDisabled(true);

    ui->accoutLine->setText("张三");
    ui->ipLine->setText("192.168.125.77");
    ui->portLine->setText("8888");
    //连接成功会触发connected信号,只需要一次
    connect(socket,&QTcpSocket::connected,this,&Widget::connnectedSlot);

    //收信号
    connect(socket,&QTcpSocket::readyRead,this,&Widget::readyReadSlot);

    connect(socket,&QTcpSocket::disconnected,this,&Widget::disconnectedSlot);
}

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


void Widget::on_connnectBtn_clicked()
{
    //连接服务器
    username=ui->accoutLine->text();
    QString ip=ui->ipLine->text();
    quint16 port=ui->portLine->text().toUInt();
    socket->connectToHost(ip,port);
    //判断是否连接成功:连接成功后,户端会自动发射一个connected信号,

}

void Widget::connnectedSlot()
{
    QMessageBox::information(this,"提示","连接成功");

    QString msg=username+"进入聊天室";
    socket->write(msg.toLocal8Bit());

    ui->sendBtn->setDisabled(false);
    ui->connnectBtn->setDisabled(true);
    ui->disconnectBtn->setDisabled(false);

}

void Widget::on_disconnectBtn_clicked()
{

    QString msg=username+"离开聊天室";
    socket->write(msg.toLocal8Bit());
    socket->disconnectFromHost();

}

void Widget::on_sendBtn_clicked()
{
    if(ui->infoLine->text().isEmpty()){
        QMessageBox::information(this,"提示","发送的消息不能为空");
        return;
    }
    QString msg=ui->infoLine->text();
    socket->write(msg.toLocal8Bit());
    ui->infoLine->setText("");
}
void Widget::readyReadSlot(){
    QByteArray msg=socket->readAll();

    ui->listWidget->addItem(QString::fromLocal8Bit(msg));
}

void Widget::disconnectedSlot()
{
    ui->sendBtn->setDisabled(true);
    ui->disconnectBtn->setDisabled(true);
    ui->connnectBtn->setDisabled(false);
    QMessageBox::information(this,"提示","断开连接成功");
}

ui:

运行结果:客户端连接之后可以成功发送信息

今日思维导图:

将聊天功能加入到仿qq登录之后:

代码:

page2.h:

cpp 复制代码
#ifndef PAGE2_H
#define PAGE2_H

#include <QWidget>
#include <QMovie>
#include <QTcpSocket>
#include <QMessageBox>
#include <QDebug>
#define PORT 8888
#define IP "192.168.125.77"

namespace Ui {
class Page2;
}

class Page2 : public QWidget
{
    Q_OBJECT

public:
    explicit Page2(QWidget *parent = nullptr);
    ~Page2();
public slots:
    void login_slot();
    void connectedSlot();
    void readyReadSlot();
private slots:
    void on_sendBtn_clicked();

private:
    Ui::Page2 *ui;

    QTcpSocket *socket;

};

#endif // PAGE2_H

widget.h:

cpp 复制代码
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QMovie>
#include <QMessageBox>
#include <QDebug>
#include <QMouseEvent>


QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

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

    void mousePressEvent(QMouseEvent *event) override;
    void mouseMoveEvent(QMouseEvent *event) override;

public slots:
    void loginButton_slot();


signals:
    void login_signal();

private:
    Ui::Widget *ui;

    QPoint p;//定义全局变量p,记录位置
public:
    static QString username;
};

#endif // WIDGET_H

main.cpp:

cpp 复制代码
#include "widget.h"
#include "page2.h"

#include <QApplication>

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

    Page2 p2;
    QObject::connect(&w,&Widget::login_signal,&p2,&Page2::login_slot);
    return a.exec();
}

page2.cpp:

cpp 复制代码
#include "page2.h"
#include "widget.h"
#include "ui_page2.h"

Page2::Page2(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Page2)
{
    ui->setupUi(this);
    QMovie *movie = new QMovie(":/111/cai.gif");
    ui->label->setMovie(movie);
    ui->label->setScaledContents(true);
    movie->start();
    //实例化客户端
    socket=new QTcpSocket(this);
    qDebug() << "实例化客户端";
    //建立connected信号和指定槽函数的连接
    connect(socket,&QTcpSocket::connected,this,&Page2::connectedSlot);
    //建立readyRead信号和指定槽函数连接
    connect(socket,&QTcpSocket::readyRead,this,&Page2::readyReadSlot);

}

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

void Page2::login_slot()
{
    qDebug() << "登录按钮";
    this->show();
    //连接客户端
    socket->connectToHost(IP,PORT);
}

void Page2::connectedSlot()
{
    //连接成功后触发该槽函数
    qDebug() << "连接成功";
    QMessageBox::information(this,"提示","连接成功");

    QString msg=Widget::username+"加入了聊天";
    socket->write(msg.toLocal8Bit());
}

void Page2::readyReadSlot()
{
    //收到服务端发送的消息时触发该槽函数
    QByteArray msg=socket->readAll();
    ui->listWidget->addItem(QString::fromLocal8Bit(msg));
}

void Page2::on_sendBtn_clicked()
{
    if(ui->infoEdit->toPlainText().isEmpty()){
        QMessageBox::information(this,"提示","发送的消息不能为空");
        return;
    }
    QString msg=ui->infoEdit->toPlainText();
    socket->write(msg.toLocal8Bit());
    ui->infoEdit->clear();
}

widget.cpp:

cpp 复制代码
#include "widget.h"
#include "ui_widget.h"
QString Widget::username="";
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    this->setFixedSize(560,430);
    this->setStyleSheet("background-color:#faf7ec");
    this->setWindowFlag(Qt::FramelessWindowHint);//无边框
    QMovie *movie = new QMovie(":/111/cai.gif");
    ui->backLabel->setMovie(movie);
    ui->backLabel->setScaledContents(true);
    movie->start();

    ui->closeButton->setStyleSheet("border-image:url(:/111/basketball.png)");


    ui->avatorLabel->resize(60,60);
    ui->avatorLabel->setStyleSheet("border-image:url(:/111/user.png);border-radius:30px");

    ui->accountLabel->setPixmap(QPixmap(":/111/account.jpg"));
    //ui->accountLabel->resize(40,40);
    ui->accountLabel->setScaledContents(true);

    ui->passwdLabel->setPixmap(QPixmap(":/111/passwd.jpg"));
    //ui->passwdLabel->resize(40,40);
    ui->passwdLabel->setScaledContents(true);

    ui->accoountLine->setPlaceholderText("账号");
    ui->passwdLine->setPlaceholderText("密码");
    ui->passwdLine->setEchoMode(QLineEdit::Password);

    ui->loginLabel->setPixmap(QPixmap(":/111/2.png"));
    ui->loginLabel->setScaledContents(true);

    ui->loginButton->setStyleSheet("background-color:#409EFF;border-radius:5px");

    connect(ui->closeButton,SIGNAL(clicked()),this,SLOT(close()));

    connect(ui->loginButton,&QPushButton::clicked,this,&Widget::loginButton_slot);

}

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


void Widget::loginButton_slot()
{
    //判断用户账号密码的正确性
    if(ui->accoountLine->text()=="admin"&&ui->passwdLine->text()=="123456"){
        username="admin";
        qDebug() << "登录成功" <<endl;
        QMessageBox::information(this,"提示","登录成功",QMessageBox::Ok);
        this->close();
        //开启新窗口,手动触发信号
        emit login_signal();
    }else{
        qDebug() << "账号或者密码错误" <<endl;
        int res=QMessageBox::information(this,"提示","账号或者密码错误,是否继续登录",QMessageBox::Ok|QMessageBox::No);
        if(res==QMessageBox::Ok){
            ui->passwdLine->setText("");
        }else{
            this->close();
        }

    }
}
void Widget::mousePressEvent(QMouseEvent *event){
    p=event->pos();
}
void Widget::mouseMoveEvent(QMouseEvent *event){
    if(event->buttons()==Qt::LeftButton)
    this->move(event->globalPos()-p);
}

page2.ui:

widget.ui:

运行结果:

相关推荐
CodeAaron4 分钟前
智慧城市新基建:AI代理IP如何让城市管理“耳聪目明”?
人工智能·tcp/ip·智慧城市
喝养乐多长不高1 小时前
HTTPS加密原理详解
网络·网络协议·http·https·证书·非对称加密·对称加密
D-river1 小时前
【Academy】HTTP 请求走私 ------ HTTP request smuggling
网络·网络协议·安全·web安全·http·网络安全
pyliumy2 小时前
在基于Arm架构的华为鲲鹏服务器上,针对openEuler 20.03 LTS操作系统, 安装Ansible 和MySQL
服务器·架构·ansible
努力学习的小廉2 小时前
深入了解Linux —— 调试程序
linux·运维·服务器
只做开心事3 小时前
Linux网络之数据链路层协议
linux·服务器·网络
AI学IT3 小时前
(安全防御)旁挂组网双机热备负载分担实验
运维·服务器·网络
已是上好佳4 小时前
介绍一下Qt中的事件过滤
java·服务器·数据库
挣扎与觉醒中的技术人4 小时前
【技术干货】三大常见网络攻击类型详解:DDoS/XSS/中间人攻击,原理、危害及防御方案
前端·网络·ddos·xss
code monkey.4 小时前
【寻找Linux的奥秘】第一章:基础指令
linux·运维·服务器