QT Day07(2)

2 基于QT的聊天室程序
2.1 问题
通过QT实现简单的网络聊天室程序。

2.2 方案
QTcpSocket类提供了一个基于TCP的套接字,它是QAbstractSocket的一个子类,通过它可以非常方便建立一个基于TCP连接和数据流传输。本案例使用该类建立一个基于局域网的图形用户界面的网络聊天室。

首先实现服务器端,服务器可以建立tcp服务,接收多个客户端的连接请求,接收客户端发送的聊天的消息,并转发到聊天室,让其它所有客户端都能看到。

然后创建客户端,客户端可以连接到指定的聊天室服务器,进入以后即可实现与该聊天室的其它客户端进行聊天。

2.3 步骤
实现此案例需要按照如下步骤进行。

步骤一:创建Server工程

终端输入:qtcreator或点击桌面qt图标。启动Qt创造器。

选择菜单"file/file or project",在"新建"对话框中依次选择"application"和"QT widgets Application",并点击"choose…"

在"项目介绍和位置"中指定项目的名称为:Server,并选择存储路径,Qt会在该路径下创建工程目录,点击"next"

在"kits"中选择"Desktop Qt 5.4.1 Gcc 64bit",前面打勾,点击"next"

在"Class information"中选择"QDialog"作为"Base class",并将"class name"设置为" ServerDialog",勾选"Generate form",点击"next" ,点击"finsh"。

步骤二:使用设计师设计界面

双击ServerDialog.ui,打开Qt设计师,开始设计界面:
在这里插入图片描述
步骤三:编写源程序头文件ServerDialog.h

双击ServerDialog.h文件,编写头文件,代码如下:

#ifndef SERVERDIALOG_H
#define SERVERDIALOG_H
#include
#include //实现基本的TCP服务器
#include
namespace Ui {
class ServerDialog;
}
class ServerDialog : public QDialog
{
Q_OBJECT
public:
explicit ServerDialog(QWidget *parent = 0);
~ServerDialog();
private slots:
//创建服务器按钮对应槽函数
void on_createButton_clicked();
//当有客户端和服务器建立连接时将发送newConnection
//调用该槽函数,完成服务器创建
void slotClientConnection();
//当服务器收到消息时,和客户端通信的套接字发送readyRead
//调用该槽函数,接收客户端发来的信息
void slotDataReceived(void);
//收到新消息调用发送newMessage
//调用该槽函数,将消息转发给所有客户端
void slotSendMessage(QByteArray);
signals:
//将收到新消息时发送该信号,参数为消息
void newMessage(QByteArray);
private:
Ui::ServerDialog ui;
//服务器对象
QTcpServer tcpServer;
//服务器端口
qint16 port;
//保存和客户端通信的socket容器
QList<QTcpSocket
> tcpClientList;
};
#endif // SERVERDIALOG_H
步骤四:编写源程序文件ServerDialog.cpp。

双击ServerDialog.cpp文件,编写源文件,代码如下:

#include “ServerDialog.h”
#include “ui_ServerDialog.h”
ServerDialog::ServerDialog(QWidget parent) :
QDialog(parent),
ui(new Ui::ServerDialog)
{
ui->setupUi(this);
//当有客户端建立连接后:发送newConnection()
connect(&tcpServer,SIGNAL(newConnection()),
this,SLOT(slotClientConnection()));
//有客户端发送信息给服务器:发送newConnection()
connect(this,SIGNAL(newMessage(QByteArray)),
this,SLOT(slotSendMessage(QByteArray)));
}
ServerDialog::~ServerDialog()
{
delete ui;
}
void ServerDialog::on_createButton_clicked()
{
qDebug("%s",func);
//获取端口号
port = ui->portLineEdit->text().toShort();
//开启tcp的服务器
if(tcpServer.listen(QHostAddress::Any,port)){
qDebug(“tcpServer creator success!”);
}
else{
qDebug(“tcpServer creator false!”);
}
//禁用“创建按钮”和“端口输入”
ui->createButton->setEnabled(false);
ui->portLineEdit->setEnabled(false);
}
//当有客户端和服务器建立连接时调用该槽函数
void ServerDialog::slotClientConnection()
{
qDebug("%s",func);
//nextPendingConnection():获取和客户端连接的tcp套接子
QTcpSocket
tcpClientSocket = tcpServer.nextPendingConnection();
//保存客户端套接子到容器
tcpClientList.append(tcpClientSocket);
//当和客户端通信的socket有消息时,将触发readyRead()信号
connect(tcpClientSocket,SIGNAL(readyRead()),this,SLOT(slotDataReceived()));
}
void ServerDialog::slotDataReceived()
{
qDebug("%s",func);
//遍历检查套接口是否有数据到来
for(int i=0; i<tcpClientList.count();i++){
if(tcpClientList.at(i)->bytesAvailable()){
//读取客户端发来的信息
QByteArray readbuf = tcpClientList.at(i)->readAll();
qDebug("%s",readbuf.data());
//显示消息到服务器ui
ui->contentListWidget->addItem(readbuf);
//发送新消息到来信号
emit newMessage(readbuf);
}
}
}
//群发消息到所有客户端
void ServerDialog::slotSendMessage(QByteArray msg)
{
qDebug("%s",func);
for(int i=0;i<tcpClientList.count();i++){
tcpClientList.at(i)->write(msg);
}
}
步骤五:编译运行

代码编辑完后,即可对工程进行编译,点击绿色按钮,即可编译运行,如果代码有错,会给出错误信息,运行结果如下图-6所示:
在这里插入图片描述
步骤六:创建Client工程

终端输入:qtcreator或点击桌面qt图标。启动Qt创造器。

选择菜单"file/file or project",在"新建"对话框中依次选择"application"和"QT widgets Application",并点击"choose…"

在"项目介绍和位置"中指定项目的名称为:Client,并选择存储路径,Qt会在该路径下创建工程目录,点击"next"

在"kits"中选择"Desktop Qt 5.4.1 Gcc 64bit",前面打勾,点击"next"

在"Class information"中选择"QDialog"作为"Base class",并将"class name"设置为"ClientDialog",勾选"Generate form",点击"next" ,点击"finsh"。

步骤七:使用设计师设计界面

双击ClientDialog.ui,打开Qt设计师,设计界面如图-7所示:
在这里插入图片描述
步骤八:编写源程序头文件ClientDialog.h

双击ClientDialog.h文件,编写头文件,代码如下:

#ifndef CLIENTDIALOG_H
#define CLIENTDIALOG_H
#include
#include
#include
#include
namespace Ui {
class ClientDialog;
}
class ClientDialog : public QDialog
{
Q_OBJECT
public:
explicit ClientDialog(QWidget *parent = 0);
~ClientDialog();
private slots:
//自定义槽函数
void slotConnected(void);//socket连接成功调用该函数
void slotDisconnected(void);//socket连接失败调用该函数
void slotDataReceived(void);//当socket数据到来调用该函数
void slotSockError(QAbstractSocket::SocketError);//socket异常处理槽函数
void on_sendButton_clicked();//“发送消息”按钮的曹函数
void on_connectButton_clicked();//“连接服务器”按钮的操作函数
public:
bool status;//标记连接状态,true->成功,false->失败
qint16 port;//端口号
QHostAddress serverIP;//服务器地址
QString userName;//用户名
QTcpSocket tcpSocket;//tcp套接字
private:
Ui::ClientDialog *ui;
};
#endif // CLIENTDIALOG_H
步骤九:编写源程序文件ClientDialog.cpp。

双击ClientDialog.cpp文件,编写源文件,代码如下:

#include “ClientDialog.h”
#include “ui_ClientDialog.h”
ClientDialog::ClientDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::ClientDialog)
{
ui->setupUi(this);
status = false;//初始化连接状态
//连接成功发送connected
connect(&tcpSocket,SIGNAL(connected()),this,SLOT(slotConnected()));
//断开连接发送disconnected
connect(&tcpSocket,SIGNAL(disconnected()),this,SLOT(slotDisconnected()));
//当套接子有数据到来时发送readyRead()信号
connect(&tcpSocket,SIGNAL(readyRead()),this,SLOT(slotDataReceived()));
//对套接口读写失败,发送error信号
connect(&tcpSocket,SIGNAL(error(QAbstractSocket::SocketError)),
this,SLOT(slotSockError(QAbstractSocket::SocketError)));
}
ClientDialog::~ClientDialog()
{
delete ui;
}
//发送消息对应的槽函数
void ClientDialog::on_sendButton_clicked()
{
if(ui->sendLineEdit->text() == “”){
return;
}
QString msg= userName + “:” + ui->sendLineEdit->text();
//qDebug() << msg;
//QByteArray buf = msg.toLocal8Bit();
if(tcpSocket.write(msg.toLocal8Bit())==-1){
qDebug(“error write”);
}
ui->sendLineEdit->clear();
}
//连接服务器按钮对应的槽函数
void ClientDialog::on_connectButton_clicked()
{
qDebug("%s",func);
if(!status){//如果没有建立连接,则连接
//获取ui界面输入的IP
QString ip = ui->serverIpLineEdit->text();
//设置服务器的IP地址
if(!serverIP.setAddress(ip)){
QMessageBox::information(this,tr(“error”),tr(“server ip address error!”));
return;
}
//获取用户名,用户名不能为空:
if(ui->userLineEdit->text() == “”){
QMessageBox::information(this,tr(“error”),tr(“User name error!”));
return;
}
userName = ui->userLineEdit->text();
//获取端口号
if(ui->portLineEdit->text() == “”){
QMessageBox::information(this,tr(“error”),tr(“Port number error!”));
return;
}
port = ui->portLineEdit->text().toShort();
//和服务器建立连接
tcpSocket.connectToHost(serverIP,port);
//状态标记为连接状态
status = true;
}
else{
QString msg=userName+tr(":Leave Chat Room");
tcpSocket.write(msg.toLocal8Bit());
//关闭和服务器的socket连接
tcpSocket.disconnectFromHost();
status=false;
}
}
//和服务器连接成功以后被调用
void ClientDialog::slotConnected(){
qDebug("%s",func);
//使能“发送消息”按钮
ui->sendButton->setEnabled(true);
//“修改连接服务器”按钮内容为”离开服务器“
ui->connectButton->setText(tr(“离开聊天室”));
//禁用:ip、port、用户名的输入
ui->serverIpLineEdit->setEnabled(false);
ui->portLineEdit->setEnabled(false);
ui->userLineEdit->setEnabled(false);
//向服务器发送进入聊天室信息
QString msg=userName+tr(":Enter Chat Room");
QByteArray buf = msg.toLocal8Bit();
tcpSocket.write(buf);
}
void ClientDialog::slotDisconnected(){
qDebug("%s",func);
status = false;
//禁用“发送消息”按钮
ui->sendButton->setEnabled(false);
//使能:ip、port、用户名的输入
ui->serverIpLineEdit->setEnabled(true);
ui->portLineEdit->setEnabled(true);
ui->userLineEdit->setEnabled(true);
ui->connectButton->setText(tr(“连接服务器”));
}
//当服务器给客户端返回信息调用该函数
void ClientDialog::slotDataReceived(){
//bytesAvailable,返回当前套接口有效数据字节数
if(tcpSocket.bytesAvailable()){
QByteArray datagram;
datagram.resize(tcpSocket.bytesAvailable());
//读取消息
tcpSocket.read(datagram.data(),datagram.size());
//显示消息到界面
QString msg=datagram.data();
ui->contentList->addItem(msg.left(datagram.size()));
}
}
void ClientDialog::slotSockError(QAbstractSocket::SocketError)
{
//打印错误信息
qDebug() << tcpSocket.errorString();
}
步骤十:编译运行

代码编辑完后,即可对工程进行编译,点击绿色按钮,即可编译运行,如果代码有错,会给出错误信息,运行结果如下图-8所示:
在这里插入图片描述
2.4 完整代码
本案例的头文

本案ServerDialog.h文件完整代码如下所示:

#ifndef SERVERDIALOG_H
#define SERVERDIALOG_H
#include
#include //实现基本的TCP服务器
#include
namespace Ui {
class ServerDialog;
}
class ServerDialog : public QDialog
{
Q_OBJECT
public:
explicit ServerDialog(QWidget *parent = 0);
~ServerDialog();
private slots:
//创建服务器按钮对应槽函数
void on_createButton_clicked();
//当有客户端和服务器建立连接时将发送newConnection
//调用该槽函数,完成服务器创建
void slotClientConnection();
//当服务器收到消息时,和客户端通信的套接字发送readyRead
//调用该槽函数,接收客户端发来的信息
void slotDataReceived(void);
//收到新消息调用发送newMessage
//调用该槽函数,将消息转发给所有客户端
void slotSendMessage(QByteArray);
signals:
//将收到新消息时发送该信号,参数为消息
void newMessage(QByteArray);
private:
Ui::ServerDialog ui;
//服务器对象
QTcpServer tcpServer;
//服务器端口
qint16 port;
//保存和客户端通信的socket容器
QList<QTcpSocket
> tcpClientList;
};
#endif // SERVERDIALOG_H
本案ServerDialog.cpp文件完整代码如下所示:

#include “ServerDialog.h”
#include “ui_ServerDialog.h”
ServerDialog::ServerDialog(QWidget parent) :
QDialog(parent),
ui(new Ui::ServerDialog)
{
ui->setupUi(this);
//当有客户端建立连接后:发送newConnection()
connect(&tcpServer,SIGNAL(newConnection()),
this,SLOT(slotClientConnection()));
//有客户端发送信息给服务器:发送newConnection()
connect(this,SIGNAL(newMessage(QByteArray)),
this,SLOT(slotSendMessage(QByteArray)));
}
ServerDialog::~ServerDialog()
{
delete ui;
}
void ServerDialog::on_createButton_clicked()
{
qDebug("%s",func);
//获取端口号
port = ui->portLineEdit->text().toShort();
//开启tcp的服务器
if(tcpServer.listen(QHostAddress::Any,port)){
qDebug(“tcpServer creator success!”);
}
else{
qDebug(“tcpServer creator false!”);
}
//禁用“创建按钮”和“端口输入”
ui->createButton->setEnabled(false);
ui->portLineEdit->setEnabled(false);
}
//当有客户端和服务器建立连接时调用该槽函数
void ServerDialog::slotClientConnection()
{
qDebug("%s",func);
//nextPendingConnection():获取和客户端连接的tcp套接子
QTcpSocket
tcpClientSocket = tcpServer.nextPendingConnection();
//保存客户端套接子到容器
tcpClientList.append(tcpClientSocket);
//当和客户端通信的socket有消息时,将触发readyRead()信号
connect(tcpClientSocket,SIGNAL(readyRead()),this,SLOT(slotDataReceived()));
}
void ServerDialog::slotDataReceived()
{
qDebug("%s",func);
//遍历检查套接口是否有数据到来
for(int i=0; i<tcpClientList.count();i++){
if(tcpClientList.at(i)->bytesAvailable()){
//读取客户端发来的信息
QByteArray readbuf = tcpClientList.at(i)->readAll();
qDebug("%s",readbuf.data());
//显示消息到服务器ui
ui->contentListWidget->addItem(readbuf);
//发送新消息到来信号
emit newMessage(readbuf);
}
}
}
//群发消息到所有客户端
void ServerDialog::slotSendMessage(QByteArray msg)
{
qDebug("%s",func);
for(int i=0;i<tcpClientList.count();i++){
tcpClientList.at(i)->write(msg);
}
}
本案ClientDialog.h文件完整代码如下所示:

#ifndef CLIENTDIALOG_H
#define CLIENTDIALOG_H
#include
#include
#include
#include
namespace Ui {
class ClientDialog;
}
class ClientDialog : public QDialog
{
Q_OBJECT
public:
explicit ClientDialog(QWidget *parent = 0);
~ClientDialog();
private slots:
//自定义槽函数
void slotConnected(void);//socket连接成功调用该函数
void slotDisconnected(void);//socket连接失败调用该函数
void slotDataReceived(void);//当socket数据到来调用该函数
void slotSockError(QAbstractSocket::SocketError);//socket异常处理槽函数
void on_sendButton_clicked();//“发送消息”按钮的曹函数
void on_connectButton_clicked();//“连接服务器”按钮的操作函数
public:
bool status;//标记连接状态,true->成功,false->失败
qint16 port;//端口号
QHostAddress serverIP;//服务器地址
QString userName;//用户名
QTcpSocket tcpSocket;//tcp套接字
private:
Ui::ClientDialog *ui;
};
#endif // CLIENTDIALOG_H
本案ClientDialog.cpp文件完整代码如下所示:

#include “ClientDialog.h”
#include “ui_ClientDialog.h”
ClientDialog::ClientDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::ClientDialog)
{
ui->setupUi(this);
status = false;//初始化连接状态
//连接成功发送connected
connect(&tcpSocket,SIGNAL(connected()),this,SLOT(slotConnected()));
//断开连接发送disconnected
connect(&tcpSocket,SIGNAL(disconnected()),this,SLOT(slotDisconnected()));
//当套接子有数据到来时发送readyRead()信号
connect(&tcpSocket,SIGNAL(readyRead()),this,SLOT(slotDataReceived()));
//对套接口读写失败,发送error信号
connect(&tcpSocket,SIGNAL(error(QAbstractSocket::SocketError)),
this,SLOT(slotSockError(QAbstractSocket::SocketError)));
}
ClientDialog::~ClientDialog()
{
delete ui;
}
//发送消息对应的槽函数
void ClientDialog::on_sendButton_clicked()
{
if(ui->sendLineEdit->text() == “”){
return;
}
QString msg= userName + “:” + ui->sendLineEdit->text();
//qDebug() << msg;
//QByteArray buf = msg.toLocal8Bit();
if(tcpSocket.write(msg.toLocal8Bit())==-1){
qDebug(“error write”);
}
ui->sendLineEdit->clear();
}
//连接服务器按钮对应的槽函数
void ClientDialog::on_connectButton_clicked()
{
qDebug("%s",func);
if(!status){//如果没有建立连接,则连接
//获取ui界面输入的IP
QString ip = ui->serverIpLineEdit->text();
//设置服务器的IP地址
if(!serverIP.setAddress(ip)){
QMessageBox::information(this,tr(“error”),tr(“server ip address error!”));
return;
}
//获取用户名,用户名不能为空:
if(ui->userLineEdit->text() == “”){
QMessageBox::information(this,tr(“error”),tr(“User name error!”));
return;
}
userName = ui->userLineEdit->text();
//获取端口号
if(ui->portLineEdit->text() == “”){
QMessageBox::information(this,tr(“error”),tr(“Port number error!”));
return;
}
port = ui->portLineEdit->text().toShort();
//和服务器建立连接
tcpSocket.connectToHost(serverIP,port);
//状态标记为连接状态
status = true;
}
else{
QString msg=userName+tr(":Leave Chat Room");
tcpSocket.write(msg.toLocal8Bit());
//关闭和服务器的socket连接
tcpSocket.disconnectFromHost();
status=false;
}
}
//和服务器连接成功以后被调用
void ClientDialog::slotConnected(){
qDebug("%s",func);
//使能“发送消息”按钮
ui->sendButton->setEnabled(true);
//“修改连接服务器”按钮内容为”离开服务器“
ui->connectButton->setText(tr(“离开聊天室”));
//禁用:ip、port、用户名的输入
ui->serverIpLineEdit->setEnabled(false);
ui->portLineEdit->setEnabled(false);
ui->userLineEdit->setEnabled(false);
//向服务器发送进入聊天室信息
QString msg=userName+tr(":Enter Chat Room");
QByteArray buf = msg.toLocal8Bit();
tcpSocket.write(buf);
}
void ClientDialog::slotDisconnected(){
qDebug("%s",func);
status = false;
//禁用“发送消息”按钮
ui->sendButton->setEnabled(false);
//使能:ip、port、用户名的输入
ui->serverIpLineEdit->setEnabled(true);
ui->portLineEdit->setEnabled(true);
ui->userLineEdit->setEnabled(true);
ui->connectButton->setText(tr(“连接服务器”));
}
//当服务器给客户端返回信息调用该函数
void ClientDialog::slotDataReceived(){
//bytesAvailable,返回当前套接口有效数据字节数
if(tcpSocket.bytesAvailable()){
QByteArray datagram;
datagram.resize(tcpSocket.bytesAvailable());
//读取消息
tcpSocket.read(datagram.data(),datagram.size());
//显示消息到界面
QString msg=datagram.data();
ui->contentList->addItem(msg.left(datagram.size()));
}
}
void ClientDialog::slotSockError(QAbstractSocket::SocketError)
{
//打印错误信息
qDebug() << tcpSocket.errorString();
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值