server
.h
#ifndef CHATSERVER_H
#define CHATSERVER_H
#include <QWidget>
#include <QTcpServer>
#include <QTcpSocket>
#include <QList>
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_newConnection_slot();
void on_readyRead_slot(); //readyRead槽函数声明
void send(QString mes); //自定义广播函数
private:
Ui::ChatServer *ui;
//定义一个服务器指针
QTcpServer *server;
//定义客户端指针,盛放连接的客户端
QList<QTcpSocket *> socketList;
};
#endif // CHATSERVER_H
.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);
ui->startBtn->setStyleSheet("hover:background-color:#409EFF");
}
ChatServer::~ChatServer()
{
delete ui;
}
//启动按钮对应的槽函数
void ChatServer::on_startBtn_clicked()
{
quint16 port =quint16( ui->portEdit->text().toInt() ); //强制转化为quint16
//将服务器设置为监听状态
server->listen(QHostAddress::Any,port);
//将相应的控件设置为不可用状态
ui->startBtn->setEnabled(false);
ui->portEdit->setEnabled(false);
//当有新用户连接到服务器时,会发出一个newconnection信号
connect(server,&QTcpServer::newConnection,this,&ChatServer::on_newConnection_slot);
}
//对应槽函数定义
void ChatServer::on_newConnection_slot()
{
QTcpSocket *socket= server->nextPendingConnection();
//将该套接字放入套接字链表中
socketList.append(socket);
//当服务器接收到客户端传过来的消息时就会触发一个readyRead信号,在该信号对应的槽函数中处理逻辑
connect(socket,&QTcpSocket::readyRead,this,&ChatServer::on_readyRead_slot);
}
//对应槽函数定义
void ChatServer::on_readyRead_slot()
{
//链表中节点删除
//判断客户端套接字是否有效。如果无效则移除
for(int i=0;i<socketList.count();i++)
{
if(socketList.at(i)->state() == false)
{
socketList.removeAt(i);
}
}
//遍历客户端的链表,判断是哪个客户端发送消息
for(quint16 i=0;i<socketList.count();i++)
{
//bytesAvailable() 获取客户端中待读数据的个数
if(socketList.at(i)->bytesAvailable())
{
//获取客户端传过来的待读数据, fromlocal8bit 接收到的信息要转化为字符
QString mes =QString::fromLocal8Bit( socketList.at(i)->readAll());
//将消息展示到list widget上
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());
}
}
client
.h
#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_connected_slot();
void on_disconnected_slot();
void on_readyRead_slot();
void on_sendBtn_clicked();
private:
Ui::ChatClient *ui;
//定义客户端套接字指针
QTcpSocket *socket;
//定义用户名
QString userName;
//定义连接状态
bool isOk;
};
#endif // CHATCLIENT_H
.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;
//将connected信号连接到自定义的槽函数中处理相关逻辑
connect(socket,&QTcpSocket::connected,this,&ChatClient::on_connected_slot);
//将disconnected信号连接到自定义的槽函数中处理相关逻辑
connect(socket,&QTcpSocket::disconnected,this,&ChatClient::on_disconnected_slot);
//当客户端接收到服务器发的消息后,会触发一个readyRead信号,在该信号对应的槽函数中书写逻辑
connect(socket,&QTcpSocket::readyRead,this,&ChatClient::on_readyRead_slot);
}
ChatClient::~ChatClient()
{
delete ui;
}
//连接服务器按钮
void ChatClient::on_connectBtn_clicked()
{
QString ip=ui->ipEdit->text();
quint16 port =quint16( ui->portEdit->text().toInt());
//判断连接状态
if(isOk == false)
{
//连接服务器
//客户端连接服务器函数
socket->connectToHost(QHostAddress(ip),port);
//一旦连接成功就会触发一个connected的信号,在该信号对应的槽函数中处理逻辑
//将按钮文本改为“断开连接”
ui->connectBtn->setText("断开连接");
isOk = true;
}else{
userName = ui->userEdit->text();
QString mes = userName +"--退出群聊";
socket->write(mes.toLocal8Bit()); //告诉服务器肘了
//将用户名、ip、端口框可用
ui->portEdit->setEnabled(true);
ui->ipEdit->setEnabled(true);
ui->userEdit->setEnabled(true);
//断开服务器
socket->disconnectFromHost();
//一旦连接成功就会触发一个disconnected的信号,在该信号对应的槽函数中处理逻辑
//将按钮文本改为“连接服务器”
ui->connectBtn->setText("连接服务器");
isOk = false;
}
}
//connect对应槽函数的定义
void ChatClient::on_connected_slot()
{
userName = ui->userEdit->text();
QString mes = userName +"--加入群聊";
socket->write(mes.toLocal8Bit()); //告诉服务器来了
//将用户名、ip、端口框禁用
ui->portEdit->setEnabled(false);
ui->ipEdit->setEnabled(false);
ui->userEdit->setEnabled(false);
}
//disconnect对应槽函数的定义
void ChatClient::on_disconnected_slot()
{
}
void ChatClient::on_readyRead_slot()
{
//获取套接字中的数据
QString mes = QString::fromLocal8Bit(socket->readAll());
//将数据显示在list widget中
ui->listWidget->addItem(mes);
}
//发送按钮对应的槽函数
void ChatClient::on_sendBtn_clicked()
{
userName = ui->userEdit->text();
QString mes = userName + ": "+ ui->mesEdit->text();
//将文本数据发送给服务器
socket->write(mes.toLocal8Bit());
//将发送数据的框中数据清空
ui->mesEdit->clear();
}