作业:利用TCP客户端和服务器实现网络聊天室(简单版QQ)
1.服务器代码
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();
void newConnection_slot(); //自定义处理newConnection信号的槽函数的声明
void readyRead_slot(); //自定义处理readyRead信号的槽函数的声明
private:
Ui::Widget *ui;
//实例化服务对象
QTcpServer *server;//实例化一个服务器对象
//创一个存放客户端的套接字的容器
QList<QTcpSocket *> clientList;
};
#endif // WIDGET_H
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->msgEdit->setEnabled(false);
ui->setBtn->setEnabled(false);
ui->disBtn->setEnabled(false);
//判断是否连接成功,如果连接成功客户端会自动发射connected,将该信号连接到自定义的槽函数中处理相关的逻辑
//因为只需要连接一次,所以我们将连接函数写在构造函数中
connect(socket,&QTcpSocket::connected,this,&Widget::connected_slot);//定义在构造函数是为了只连接一次
//此时说明服务器和客户端此时已经建立好连接,如果服务器发来数据,该客户端会自动发射readRead信号
connect(socket,&QTcpSocket::readyRead,this,&Widget::readyRead_slot);
//判断是否断开成功,如果成功断开连接,客户端自动发射disconnect信号
connect(socket,&QTcpSocket::disconnected,this,&Widget::dis_slot);
}
Widget::~Widget()
{
delete ui;
}
//链接服务器按钮对应的槽函数
void Widget::on_connectStn_clicked()
{
//获取ui界面上的IP和端口号
uesrName=ui->usrnameEdit->text();
QString ip= ui->ipEdit->text();
quint16 port=ui->portEdit->text().toUInt();//转换成整型
//客户端连接链接服务器
socket->connectToHost(ip,port);
}
//连接成功对应的槽函数实现
void Widget::connected_slot()
{
//告诉服务器 我来了
QString msg = uesrName + ":进入聊天室";
//将信息发送给服务器
socket ->write(msg.toLocal8Bit());
//将ui界面上的控价进行相关设置
ui->usrnameEdit->setEnabled(false);
ui->ipEdit->setEnabled(false);
ui->portEdit->setEnabled(false);
ui->connectStn->setEnabled(false);
ui->msgEdit->setEnabled(true);
ui->setBtn->setEnabled(true);
ui->disBtn->setEnabled(true);
}
void Widget::readyRead_slot()//readyread对应的槽函数
{
//说明服务器给客户端发来数据
QByteArray msg = socket->readAll();
//将数据放入到ui界面中
ui->listWidget->addItem(QString::fromLocal8Bit(msg));
}
void Widget::dis_slot()
{
ui->usrnameEdit->setEnabled(true);
ui->ipEdit->setEnabled(true);
ui->portEdit->setEnabled(true);
ui->connectStn->setEnabled(true);
ui->msgEdit->setEnabled(false);
ui->setBtn->setEnabled(false);
ui->disBtn->setEnabled(false);
}
void Widget::on_setBtn_clicked()//发送按钮对应的槽函数处理
{
//获取ui界面上的文本内容
QString msg =uesrName+":"+ ui->msgEdit->text();
//将信息发送给服务器
socket->write(msg.toLocal8Bit());
//将msg的文本清空
ui->msgEdit->clear();
}
void Widget::on_disBtn_clicked()//断开按钮对应的槽函数处理
{
QString msg = uesrName+":"+ "离开了聊天室,尔等也退下吧";
socket->write(msg.toLocal8Bit());
socket->disconnectFromHost();
}
服务器 ui界面:
2.客户端代码
second.h
cpp
复制代码
#ifndef SECOND_H
#define SECOND_H
#include <QWidget>
#include<QIcon>
#include<QTcpServer>//服务器头文件
#include<QTcpSocket>//客户端头文件
#include<QMessageBox>//消息对话框
#include<QDebug>//调试类
namespace Ui {
class Second;
}
class Second : public QWidget
{
Q_OBJECT
public slots:
void jump_slot();//接收跳转信号函数
public:
explicit Second(QWidget *parent = nullptr);
~Second();
private slots:
void on_connectBtn_clicked();//链接服务器对应的槽函数声明
void connected_solt();
void readyRead_slot();
void dis_slot();
void on_sendBtn_clicked();
void on_disBtn_clicked();
private:
Ui::Second *ui;
//实例化一个客户端对象
QTcpSocket *socket;
//定义一个用户名的变量
QString userName;
};
#endif // SECOND_H
cpp
复制代码
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include<QMovie>//动态图
#include<QPixmap>//图片
#include<QDebug>//输出
#include<QPushButton>//按钮类
#include<QMessageBox>//信息类
#include<QIcon>//图片
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
signals://自定义跳转信号函数
void jump();
private slots:
//void on_pushButton_2_clicked();
void my_slot();//自己定义的槽函数
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
main.cpp
cpp
复制代码
#include "widget.h"
#include"second.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
//实例化第二个窗口的对象
Second s;
QObject::connect(&w,&Widget::jump,&s,&Second::jump_slot);
return a.exec();
}
second.cpp
cpp
复制代码
#include "second.h"
#include "ui_second.h"
void Second::jump_slot()//跳转信号槽函数
{
this->show();//将自己的界面进行展示
}
Second::Second(QWidget *parent) :
QWidget(parent),
ui(new Ui::Second)
{
ui->setupUi(this);
//第二个界面的窗口设置
this->setWindowTitle("划水摆烂群");
this->setWindowIcon(QIcon(":/pictrue/eaeb1d87_E780070_63de2b7c.png"));
//ui->listWidget->setStyleSheet("QListWidget { background-color: transparent; }");//设置背景为透明色
//给客户端实例化空间
socket =new QTcpSocket(this);
//初始化界面(未连接服务器时)
ui->msgEdit->setEnabled(false);//消息对话框不可用
ui->sendBtn->setEnabled(false);//发送按钮不可用
ui->disBtn->setEnabled(false);//离线不可用
//判断是否连接成功,如果连接成功客户端会自动发射connected,将该信号连接到自定义的槽函数中处理相关的逻辑
//因为只需要连接一次,所以我们将连接函数写在构造函数中
connect(socket,&QTcpSocket::connected,this,&Second::connected_solt);//定义在构造函数是为了只连接一次
//此时说明服务器和客户端此时已经建立好连接,如果服务器发来数据,该客户端会自动发射readRead信号
connect(socket,&QTcpSocket::readyRead,this,&Second::readyRead_slot);
}
Second::~Second()
{
delete ui;
}
void Second::on_connectBtn_clicked()//链接服务器对应的槽函数
{
//获取ui界面上的IP和端口号
userName=ui->usernameEdit->text();//获取用户名
QString ip=ui->ipEdit->text();//获取ip
quint16 port=ui->portEdit_2->text().toUInt();//获取端口号
//客户端连接服务器
socket->connectToHost(ip,port);
}
void Second::connected_solt()//连接成功对应的槽函数
{
//告诉服务器我上线了
QString msg = userName + ":已上线";
//将消息发送给服务器
socket ->write(msg.toLocal8Bit());
//重新设置ui界面上的控件
ui->usernameEdit->setEnabled(false);
ui->ipEdit->setEnabled(false);
ui->portEdit_2->setEnabled(false);
ui->connectBtn->setEnabled(false);
ui->msgEdit->setEnabled(true);
ui->sendBtn->setEnabled(true);
ui->disBtn->setEnabled(true);
}
void Second::readyRead_slot()
{
//说明服务器给客户端发来数据
QByteArray msg = socket->readAll();
//将数据放入到ui界面中
ui->listWidget->addItem(QString::fromLocal8Bit(msg));
}
void Second::dis_slot()
{
ui->usernameEdit->setEnabled(true);
ui->ipEdit->setEnabled(true);
ui->portEdit_2->setEnabled(true);
ui->connectBtn->setEnabled(true);
ui->msgEdit->setEnabled(false);
ui->sendBtn->setEnabled(false);
ui->disBtn->setEnabled(false);
}
void Second::on_sendBtn_clicked()//发送按钮对应的槽函数
{
//获取ui界面上的文本内容
QString msg =userName+":"+ ui->msgEdit->text();
//将信息发送给服务器
socket->write(msg.toLocal8Bit());
//将msg的文本清空
ui->msgEdit->clear();
}
void Second::on_disBtn_clicked()//离线按钮对应的槽函数
{
QString msg = userName+":"+ "离开了聊天室,尔等也退下吧";
socket->write(msg.toLocal8Bit());
socket->disconnectFromHost();
}
cpp
复制代码
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//窗口图标设计
this->setWindowTitle("腾讯QQ");
this->setWindowIcon(QIcon(":/pictrue/20573cf63610bed.jpg"));
//连接登录Btn信号与槽
connect(ui->pushButton_2,&QPushButton::clicked,this,&Widget::my_slot);
ui->zhuceBtn->setStyleSheet("border:1px solid transparent;");
ui->mimaBtn->setStyleSheet("border:1px solid transparent;");//取消边框
/**********************标签设置****************************/
//设置标签背景(动态图)
// QMovie *mv = new QMovie("/*************路径*************/");
// ui->beijinglabel->setMovie(mv);
// mv->start();
//让标签自动使用标签
ui->beijinglabel->setPixmap(QPixmap(":/pictrue/wKjg2lvGWoCAJlJxAADOBePmF24715.jpg"));
ui->beijinglabel->setScaledContents(true);
//设置左上角的标签
// ui->qqlable->setPixmap(QPixmap(":/pictrue/20573cf63610bed.jpg"));
// ui->qqlable->setScaledContents(true);
// ui->qqlable->resize(30,30);//重新设置大小
/**********************登录设置*******************************/
}
Widget::~Widget()
{
delete ui;
}
void Widget::my_slot()//登录按钮对应的槽函数
{
QString userName = ui->zhanghaoEdit->text();//获取账号
QString passWord = ui->mimaEdit->text();//获取密码
//判断登录条件是否满足
if(userName=="admin"&&passWord=="123456")
{
//满足登录条件跳转到聊天室页面
// qDebug() << "deng";
// this->close();
emit jump();
this->hide();//将自己的页面隐藏
}else
{
// qDebug() << "";
QMessageBox::information(this,"提示:","账号或密码错误请重新输入");
//ui->zhanghaoEdit->clear();
}
}
second的ui界面
实现效果:
运行出的窗口
密码输入错误弹出的消息对话框和启动服务器成功界面
输入信息上线成功显示界面
消息发送成功界面
离线显示下线信息