基于qt的小型聊天室代码

linux小作业,在虚拟机中安装qt并使用实现服务端和客户端的连接,实现局域网聊天的内容

环境:centos7(适用于绝大多数本科教学环境)

总体设计

系统架构:

客户端-服务器架构:聊天室采用典型的客户端-服务器架构,客户端负责用户交互和显示,服务器负责消息处理和转发。

服务器端设计:

网络监听:使用socket编程接口创建TCP监听套接字。定监听地址和端口,开始监听客户端连接。

连接管理:采用多线程方式处理客户端连接。为每个连接创建一个会话,记录用户信息和连接状态。

消息处理:接收客户端发送的消息,解析消息内容。根据消息类型进行相应处理,如广播消息、私聊消息等。封装响应消息并发送给目标客户端。

用户管理:维护在线用户列表,记录用户名、连接状态等信息。实现用户登录、注销、查找等功能。

日志记录:记录系统运行日志和用户行为日志,方便后续分析和问题排查。

性能优化:使用多路复用技术提高I/O处理效率。优化数据结构,减少内存占用和查找时间。合理使用缓存和异步处理,提高系统响应速度。

客户端设计:

用户交互:设计简洁明了的用户界面,支持文本输入。实现用户登录等交互操作。

消息发送/接收:与服务器端建立连接,发送和接收消息。解析服务器返回的响应消息,更新用户界面。

消息展示:在聊天窗口中展示接收到的消息。

异常处理:处理网络连接异常、消息解析错误等异常情况。给出友好提示信息,引导用户重新连接或重新发送消息。

以下为示例代码:

(读者重点掌握socket编程和通信)

//服务器server:
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    mserver = new QTcpServer(this);
    msocket = NULL;
    connect(mserver,&QTcpServer::newConnection,this,&MainWindow::new_client);
}
MainWindow::~MainWindow()
{
    delete ui;
}
//监听——启动服务器
void MainWindow::on_pushButton_clicked()
{
    if( ui->textEdit->toPlainText() == "" ){            //判断是否为空
        ui->textBrowser->append("服务器启动失败,请输入要监听的端口号!");
    }else{
        mserver->listen(QHostAddress::Any,ui->textEdit->toPlainText().toUShort());
        ui->textBrowser->append("服务器启动成功,正在监听端口"+ui->textEdit->toPlainText()+"!");
    }
}
//接受连接
void MainWindow::new_client()
{
    //获取与客户端通信的套接字
    msocket = mserver->nextPendingConnection();

    socketlist.append(msocket);         //将客户端的套接字加入容器中

    //4.使用socket的write函数向客户端发送数据
    msocket->write("服务器连接成功!");

    //获取客户端IP并显示
    QString ip = msocket->peerAddress().toString();
    ip.remove("::ffff:");
    quint16 port = msocket->peerPort();
    QString tmp = QString("客户端[%1:%2] 已上线!").arg(ip).arg(port);
    ui->textBrowser->append(tmp);
    connect(msocket,&QTcpSocket::readyRead,this,&MainWindow::read_data);
}
//读取数据
void MainWindow::read_data()
{
    //获取信号发送者
    QTcpSocket *msocket1 = dynamic_cast<QTcpSocket*>(sender());

    //读取数据
    QString msg = msocket1->readAll();
    //获取对方IP和端口
    QString ip = msocket1->peerAddress().toString();
    quint16 port = msocket1->peerPort();
    ip.remove("::ffff:");
    //quint16 port = msocket1->peerPort();
    //QString tmp = QString("客户端[%1:%2]:%3").arg(ip).arg(port).arg(msg);
    if( msg != "@断开连接@" ){              //如果传过来的不是断开连接的信息
        QString tmp = msg;
        ui->textBrowser->append(tmp);

        //传送到每个客户端里面
        for(int i = 0 ; i < socketlist.size() ; i ++ ){
            socketlist[i]->write(tmp.toUtf8());
        }
    }else{              //如果传过来是断开连接的信息
        //num--;          //在线人数减少
        QString tmp = QString("客户端[%1:%2] 已下线!").arg(ip).arg(port);
        ui->textBrowser->append(tmp);
        //QString tmp = "系统信息:"+ui->textEdit_2->toPlainText();
        //send_data(tmp);;

    }

}

//断开连接
void MainWindow::on_pushButton_2_clicked()
{
    //断开连接
    ui->textBrowser->append("服务器已经关闭!");
    mserver->disconnect();
    //num = 0;

}

//发送按钮
void MainWindow::on_pushButton_3_clicked()
{

    //向客户端发送信息
    //获取与客户端通信的套接字
    //QTcpSocket *msocket = mserver->nextPendingConnection();
    //使用socket的write函数向客户端发送数据
    QString tmp = "系统信息:"+ui->textEdit_2->toPlainText();
    //注意这里要toUtf8,否则会报错
    //msocket->write(tmp.toUtf8());
    send_data(tmp);


}

 //发送信息到客户端
void MainWindow::send_data(QString which){
    //向每个客户端发送
    for(int i = 0 ; i < socketlist.size() ; i++ ){
        socketlist[i]->write(which.toUtf8());
    }

    //服务器本身日志添加
    ui->textBrowser->append(which);

}
//客户端client:
#include "mainwindow.h"
#include "ui_mainwindow.h"

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

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

//连接服务器
void MainWindow::on_pushButton_2_clicked()
{
    if( ui->textEdit_4->toPlainText() == "" ){
        QMessageBox::warning(this,tr("提示"),tr("请输入聊天用户名"),tr("确定"));
        return;
    }else if( ui->textEdit->toPlainText() == "" ){
        QMessageBox::warning(this,tr("提示"),tr("请输入IP地址"),tr("确定"));
        return;
    }else if( ui->textEdit_2->toPlainText() == "" ){
        QMessageBox::warning(this,tr("提示"),tr("请输入端口"),tr("确定"));
        return;
    }
    //存储id名字
    idname = ui->textEdit_4->toPlainText();
    msocket = new QTcpSocket(this);
    //关联读数据信号(当QTcpSocket有数据可读会发送readyRead信号--关联槽函数)
    connect(msocket,&QTcpSocket::readyRead,this,&MainWindow::read_data);
    //调用对象方法链接服务器(connectToHost(服务器的IP, 端口))
    //msocket->connectToHost(ui->textEdit->toPlainText(),ui->textEdit_2->toPlainText().toUShort());
    msocket->connectToHost( QHostAddress::LocalHost,ui->textEdit_2->toPlainText().toUShort());


    //禁用按钮以及输入框(412,2),防止重复点击
    ui->pushButton_2->setDisabled(true);
    ui->textEdit->setDisabled(true);
    ui->textEdit_2->setDisabled(true);
    ui->textEdit_4->setDisabled(true);
}

void MainWindow::read_data()
{
    //读取数据
    QString msg = msocket->readAll();
    ui->textBrowser->append(msg);
}


//发送
void MainWindow::on_pushButton_clicked()
{
    if( msocket->state() == QAbstractSocket::ConnectedState ){      //判断连接状态:如果连接
        //向服务器发送数据
        QString data = QString("%1:%2").arg(idname).arg(ui->textEdit_3->toPlainText());
        msocket->write(data.toUtf8());
    }
    //客户端日志
    //QString tmp = QString("客户端:%1").arg(data);
    //ui->textBrowser->append(tmp);
}

//断开连接
void MainWindow::on_pushButton_3_clicked()
{
    if( msocket->state() == QAbstractSocket::ConnectedState ){      //判断连接状态:如果连接
        //断开前发送信息给客户端
        QString data = "@断开连接@";
        msocket->write(data.toUtf8());
        //主动和对方断开连接
        msocket->disconnectFromHost();
        msocket->close();

    }

    //解除禁用按钮以及输入框(412,2)
    ui->pushButton_2->setDisabled(false);
    ui->textEdit->setDisabled(false);
    ui->textEdit_2->setDisabled(false);
    ui->textEdit_4->setDisabled(false);

}

 

         如图所示 简单的UI就制作完成啦

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值