首先是服务端的代码widget.cpp部分
#include "chatserver.h"
#include "ui_chatserver.h"
chatserver::chatserver(QWidget *parent)
: QWidget(parent)
, ui(new Ui::chatserver)
{
ui->setupUi(this);
//实例化服务器
server =new QTcpServer(this);
}
chatserver::~chatserver()
{
delete ui;
}
//启动按钮对应的槽函数
void chatserver::on_startbtn_clicked()
{
quint16 port=quint16(ui->portEdit->text().toInt());
//将服务器设置为监听状态
if(server->listen(QHostAddress::Any,port))
{
qDebug()<<"服务器创建成功";
}
else
{
qDebug()<<"服务器创建失败";
}
//将相应的控件设置为不可用状态
//当有新的客户端连接到该服务器后,会发出一个newconnection信号
connect(server,&QTcpServer::newConnection,this,&chatserver::on_newConnect_slots);
ui->startbtn->colorCount();
//
}
//chatserver对应槽函数的定义
void chatserver::on_newConnect_slots()
{
QTcpSocket *socket= server->nextPendingConnection();
//将该套接字放入链表中
socketList.append(socket);
//当服务器接收到客服端传过来的消息时,就会触发一个readyRead信号
connect(socket,&QTcpSocket::readyRead,this,&chatserver::on_readyRead_slots);
}
//readyRead对应槽函数的定义
void chatserver::on_readyRead_slots()
{
//遍历客服端的链表,判断是哪一个客服端发送消息
for (quint16 i=0;i<socketList.count();i++) {
//bytesAvailable:获取客服端中待读数据的个数
if(socketList.at(i)->bytesAvailable())
{
//readALL:获取客服端传过来的待读数据,无参数,返回值:QByteArray类型的数据
QString mes=QString::fromLocal8Bit(socketList.at(i)->readAll());
//将消息展示到listwidget上面
ui->listWidget->addItem(mes);
//同时要将该消息进行广播出去
send(mes);
}
}
}
//自定义发送消息函数
void chatserver::send(QString mes)
{
for (int i=0;i<socketList.count();i++) {
socketList.at(i)->write(mes.toLocal8Bit());
}
}
然后是头文件部分
#ifndef CHATSERVER_H
#define CHATSERVER_H
#include <QWidget>
#include <QTcpServer>
#include <QTcpSocket>
#include <QList>
#include <QDebug>
QT_BEGIN_NAMESPACE
namespace Ui { class chatserver; }
QT_END_NAMESPACE
class chatserver : public QWidget
{
Q_OBJECT
public:
chatserver(QWidget *parent = nullptr);
~chatserver();
private slots:
void on_startbtn_clicked();
void on_newConnect_slots();
void on_readyRead_slots();
void send(QString mes); //自定义广播函数
private:
Ui::chatserver *ui;
//定义一个服务器指针
QTcpServer *server;
//定义客服端指针,盛放连接的客服端
QList<QTcpSocket *> socketList;
};
#endif // CHATSERVER_H
最后是主函数main.cpp部分
#include "chatserver.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
chatserver w;
w.show();
return a.exec();
}
因为网络聊天设计网络部分,需要在.pro文件内写入network,只需要在第一行最后填写network即可
QT += core gui network
//QT += network
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++11
下面是客户端的代码
首先也是widget.cpp部分的
#include "chatclient.h"
#include "ui_chatclient.h"
chatclient::chatclient(QWidget *parent)
: QWidget(parent)
, ui(new Ui::chatclient)
{
ui->setupUi(this);
//实例化socket
socket = new QTcpSocket(this);
//给连接状态初始值
isOk = false;
//将connect信号连接到自定义的槽函数中处理相关逻辑
connect(socket,&QTcpSocket::connected,this,&chatclient::on_connect_slots);
connect(socket,&QTcpSocket::disconnected,this,&chatclient::on_disconnect_slots);
//当客户端接收到服务器发的消息后,会触发一个readyRead信号
connect(socket,&QTcpSocket::readyRead,this,&chatclient::on_readyRead_slots);
}
chatclient::~chatclient()
{
delete ui;
}
//连接服务器对应按钮的槽函数
void chatclient::on_connectbtn_clicked()
{
QString ip=ui->ipEdit->text();
quint16 port= ui->portEdit->text().toInt();
//判断连接状态
if(isOk == false)
{
//连接服务器
//connectToHost 功能:客服端连接服务器函数 参数:主机地址,端口号
socket->connectToHost(QHostAddress(ip),port);
//一旦连接成功,就会触发一个connected的信号,在该信号中处理逻辑
//将按钮文本改为"断开连接"
ui->connectbtn->setText("断开连接");
isOk =true;
ui->usernameEdit->setEnabled(false);
ui->ipEdit->setEnabled(false);
ui->portEdit->setEnabled(false);
}
else
{
userName=ui->usernameEdit->text();
QString mess =userName + "离开群聊";
socket->write(mess.toLocal8Bit());
//断开服务器
socket->disconnectFromHost();
//一旦连接成功,就会触发一个disconnected的信号
//将按钮文本改为"连接服务器"
ui->connectbtn->setText("连接服务器");
isOk =false;
ui->usernameEdit->setEnabled(true);
ui->ipEdit->setEnabled(true);
ui->portEdit->setEnabled(true);
}
}
//connected信号对应槽函数的定义
void chatclient::on_connect_slots()
{
userName=ui->usernameEdit->text();
QString mes =userName + "加入群聊";
socket->write(mes.toLocal8Bit()); //告诉服务器我来了
}
//disconnected信号对应槽函数的定义
void chatclient::on_disconnect_slots()
{
}
//readyRead信号对应槽函数的定义
void chatclient::on_readyRead_slots()
{
//获取套接字中的数据
QString mes =QString::fromLocal8Bit(socket->readAll());
//将数据显示在listWidget中
ui->listWidget->addItem(mes);
}
//发送按钮对应的槽函数
void chatclient::on_sendbtn_clicked()
{
userName =ui->usernameEdit->text();
QString mes = userName +":"+ ui->mesEdit->text();
//将数据发送给服务器
socket->write(mes.toLocal8Bit());
//发送完后将数据框内的数据清空
ui->mesEdit->clear();
}
头文件部分
#ifndef CHATCLIENT_H
#define CHATCLIENT_H
#include <QWidget>
#include <QTcpSocket>
#include <QHostAddress>
QT_BEGIN_NAMESPACE
namespace Ui { class chatclient; }
QT_END_NAMESPACE
class chatclient : public QWidget
{
Q_OBJECT
public:
chatclient(QWidget *parent = nullptr);
~chatclient();
private slots:
void on_connectbtn_clicked();
void on_connect_slots();
void on_disconnect_slots();
void on_readyRead_slots();
void on_sendbtn_clicked();
private:
Ui::chatclient *ui;
//定义客户端套接字指针
QTcpSocket *socket;
//定义用户名
QString userName;
//定义bool类型数据,表示连接状态
bool isOk;
};
#endif // CHATCLIENT_H
主函数main.cpp
#include "chatclient.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
chatclient w;
w.show();
return a.exec();
}
最后的图像化界面
服务端
客户端部分