基于QT的网络聊天室

效果:
在这里插入图片描述

服务器

头文件

#ifndef SERVERNETDIALOG_H
#define SERVERNETDIALOG_H

#include <QDialog>
#include <QTcpServer>
#include <QTcpSocket>
#include <QDebug>
#include <QTimer>

namespace Ui {
class serverNetDialog;
}

class serverNetDialog : public QDialog
{
    Q_OBJECT

public:
    explicit serverNetDialog(QWidget *parent = 0);
    ~serverNetDialog();

private slots:
    //创建服务器按钮对应槽函数
    void on_pushButton_creatr_clicked();
    //响应客户端连接请求的槽函数
    void onNewConnection();
    //接收客户端消息的槽函数
    void onReadyRead();
    //转发聊天消息给其他客户端
    void sendMessage(const QByteArray& buf);
    //定时器定时删除无效连接套接字槽函数
    void onTimeOut();

private:
    Ui::serverNetDialog *ui;
    QTcpServer tcpserver;
    quint16 port;//服务器端口
    QList<QTcpSocket *> tcpClientList;//容器:保存所有和客户端通信的套接字
    QTimer timer;//定时器,定时检查断开连接的套接字
};

#endif // SERVERNETDIALOG_H

源文件

#include "servernetdialog.h"
#include "ui_servernetdialog.h"

#pragma execution_character_set("utf-8")

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

    //当有客户端向服务器发送连接请求,发送信号
    connect(&tcpserver,SIGNAL(newConnection()),this,SLOT(onNewConnection()));
    connect(&timer,SIGNAL(timeout()),SLOT(onTimeOut()));
}

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

//创建服务器按钮对应槽函数
void serverNetDialog::on_pushButton_creatr_clicked()
{
    //获取端口号
    port = ui->lineEdit_port->text().toShort();
    //设置服务器IP和端口
    if(tcpserver.listen(QHostAddress::Any,port)== true){
        qDebug() << "创建服务器成功。";

        //禁用按钮与输入框
        ui->pushButton_creatr->setEnabled(false);
        ui->lineEdit_port->setEnabled(false);

        //开启定时器
        timer.start(3000);
    }
    else{
        qDebug() << "创建服务器失败!";
    }

}

//响应客户端连接请求的槽函数
void serverNetDialog::onNewConnection()
{
    //获取和客户端通信的套接字
    QTcpSocket* tcpClient = tcpserver.nextPendingConnection();
    //保存套接字到容器
    tcpClientList.append(tcpClient);
    //当客户端向服务器发送消息时,通信套接字发送信号:readyRead
    connect(tcpClient,SIGNAL(readyRead()),this,SLOT(onReadyRead()));
}
//接收客户端消息的槽函数
void serverNetDialog::onReadyRead()
{
    for(int i = 0;i < tcpClientList.size();i++)
    {
        //bytesAvailable:获取当前套接字等待读取消息字节数
        //返回0表示没消息
        //返回>0,说明当前套接字有消息到来
        if(tcpClientList.at(i)->bytesAvailable())
        {
            //读取消息并保存
            //readAll:读取全部内容
            QByteArray buf = tcpClientList.at(i)->readAll();
            //显示聊天消息
            ui->listWidget->addItem(buf);
            //最新消息显示在底部
            ui->listWidget->scrollToBottom();
            //转发消息给所有在线客户端
            sendMessage(buf);
        }
    }
}
//转发聊天消息给其他客户端
void serverNetDialog::sendMessage(const QByteArray& buf)
{
    for(int i = 0;i < tcpClientList.size();i++)
    {
        tcpClientList.at(i)->write(buf);
    }
}
//定时器定时删除无效连接套接字槽函数
void serverNetDialog::onTimeOut()
{
    //遍历容器中保存的客户端通信套接字是否已经断开连接,如果是则删除
    for(int i = 0;i < tcpClientList.size();i++)
    {
        //state:获取套接字状态,0为断开连接
        if(tcpClientList.at(i)->state() == QAbstractSocket::UnconnectedState)
        {
            tcpClientList.removeAt(i);
            --i;//将删除的套接字后的个数往前提一个
        }
    }
}

ui界面
在这里插入图片描述

客户端

头文件

#ifndef CLIENTNETDIALOG_H
#define CLIENTNETDIALOG_H

#include <QDialog>
#include <QTcpSocket>
#include <QHostAddress>
#include <QMessageBox>
#include <QDebug>

namespace Ui {
class clientNetDialog;
}

class clientNetDialog : public QDialog
{
    Q_OBJECT

public:
    explicit clientNetDialog(QWidget *parent = 0);
    ~clientNetDialog();

private slots:
    //发送消息槽函数
    void on_pushButton_send_clicked();
    //连接到服务器槽函数
    void on_pushButton_connect_clicked();

    //和服务器连接成功时执行的槽函数
    void onConnected();
    //和服务器断开连接时执行的槽函数
     void onDisConnct();
     //接收聊天消息的槽函数
     void onReadyRead();
     //网络异常时执行的槽函数
     void onError();

private:
    Ui::clientNetDialog *ui;
    bool status;//状态标识:在线/离线
    QTcpSocket tcpSocket;//和服务器通信的套接字
    QHostAddress serverIP;//服务器ip
    quint16 serverPort;//服务器端口
    QString name;//聊天室昵称
};

#endif // CLIENTNETDIALOG_H

源文件

#include "clientnetdialog.h"
#include "ui_clientnetdialog.h"

#pragma execution_character_set("utf-8")

clientNetDialog::clientNetDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::clientNetDialog)
{
    ui->setupUi(this);
    status = false;//初始化为离线状态
    connect(&tcpSocket,SIGNAL(connected()),this,SLOT(onConnected()));
    connect(&tcpSocket,SIGNAL(disconnected()),this,SLOT(onDisConnct()));
    connect(&tcpSocket,SIGNAL(readyRead()),this,SLOT(onReadyRead()));
    connect(&tcpSocket,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(onError()));
}

clientNetDialog::~clientNetDialog()
{
    delete ui;
}
//发送消息槽函数
void clientNetDialog::on_pushButton_send_clicked()
{
    //获取用户输入聊天消息
    QString msg = ui->lineEdit_messge->text();
    if(msg == ""){
        return;
    }
    else{
        msg = name + ":" + msg;
        //发送聊天消息
        tcpSocket.write(msg.toUtf8());
        //清空消息输入框
        ui->lineEdit_messge->clear();
    }
}
//连接到服务器槽函数
void clientNetDialog::on_pushButton_connect_clicked()
{
    //如果是离线状态,建立和服务器的连接
    if(status == false){
        //获取服务器IP
        serverIP.setAddress(ui->lineEdit_ip->text());
        //获取服务器端口号
        serverPort = ui->lineEdit_port->text().toShort();
        //获取聊天室名字
        name = ui->lineEdit_name->text();
        //向服务器发送连接请求
        //成功:发送信号connect
        //失败:发送信号error
        tcpSocket.connectToHost(serverIP,serverPort);
    }
    //如果是在线状态,断开和服务器的连接
    else{
        //向服务器发送离开聊天室提示消息
        QString msg = name + ":离开聊天室。";
        //toUtf8:QString转换成QByteArray
        tcpSocket.write(msg.toUtf8());

        //断开连接,会发送信号:disconnect
        tcpSocket.disconnectFromHost();
    }
}
//和服务器连接成功时执行的槽函数
void clientNetDialog::onConnected()
{
    status = true;//在线状态
    ui->pushButton_send->setEnabled(true);//恢复发送消息按钮使能
    ui->lineEdit_ip->setEnabled(false);//禁用IP
    ui->lineEdit_port->setEnabled(false);//禁用端口
    ui->lineEdit_name->setEnabled(false);//禁用聊天室昵称
    ui->pushButton_connect->setText("离开聊天室");

    //向服务器发送进入聊天室提示消息
    QString msg = name + ":进入聊天室。";
    //toUtf8:QString转换成QByteArray
    tcpSocket.write(msg.toUtf8());
}
//和服务器断开连接时执行的槽函数
 void clientNetDialog::onDisConnct()
 {
     status = false;//在线状态
     ui->pushButton_send->setEnabled(false);//恢复发送消息按钮使能
     ui->lineEdit_ip->setEnabled(true);//禁用IP
     ui->lineEdit_port->setEnabled(true);//禁用端口
     ui->lineEdit_name->setEnabled(true);//禁用聊天室昵称
     ui->pushButton_connect->setText("连接服务器");
 }
 //接收聊天消息的槽函数
 void clientNetDialog::onReadyRead()
 {
    if(tcpSocket.bytesAvailable()){
        //接收消息
        QByteArray buf = tcpSocket.readAll();
        //显示消息
        ui->listWidget->addItem(buf);
        ui->listWidget->scrollToBottom();
    }
 }
 //网络异常时执行的槽函数
 void clientNetDialog::onError()
 {
     //errorString():获取网络异常的原因
    QMessageBox::critical(this,"ERROR",tcpSocket.errorString());
 }

ui界面
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值