服务器
.h
#ifndef CHATSERVER_H
#define CHATSERVER_H
#include <QMainWindow>
#include <QTcpServer>
#include <QTcpSocket>
#include <QList>
#include <QDebug>
QT_BEGIN_NAMESPACE
namespace Ui { class ChatServer; }
QT_END_NAMESPACE
class ChatServer : public QMainWindow
{
Q_OBJECT
public:
ChatServer(QWidget *parent = nullptr);
~ChatServer();
void send(QString mes);
private slots:
void on_pushButton_clicked();
void on_newConnection_slot();
void on_readyRead_slsot();
private:
Ui::ChatServer *ui;
//定义一个服务器指针
QTcpServer *server;
//定义一个客户端指针,存放连接的客户端
QList<QTcpSocket *> socketList;
};
#endif // CHATSERVER_H
.cpp
#include "chatserver.h"
#include "ui_chatserver.h"
ChatServer::ChatServer(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::ChatServer)
{
ui->setupUi(this);
//实例化服务器
server = new QTcpServer(this);
}
ChatServer::~ChatServer()
{
delete ui;
}
//启动服务器
void ChatServer::on_pushButton_clicked()
{
quint16 port = quint16(ui->portEdit->text().toInt());
//将服务器设置为监听状态
if(server->listen(QHostAddress::Any, port))
{
qDebug()<<"服务器创建成功";
}else{
qDebug()<<"服务器创建失败";
}
//将相应控件设置为不可用
ui->portEdit->setEnabled(false);
ui->pushButton->setEnabled(false);
//有新客户端连接到服务器后,发送一个newConnecttion信号
connect(server, &QTcpServer::newConnection, this, &ChatServer::on_newConnection_slot);
}
void ChatServer::on_newConnection_slot()
{
QTcpSocket *socket = server->nextPendingConnection();
//将套接字放图套接字链表中
socketList.append(socket);
connect(socket, &QTcpSocket::readyRead, this, &ChatServer::on_readyRead_slsot);
}
void ChatServer::on_readyRead_slsot()
{
//判断客户端套接字是否有效,无效则移除
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++)
{
if(socketList.at(i)->bytesAvailable())
{
//获取客户端传来的数据
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());
}
}
客户端
.h
#ifndef CHATCLIENT_H
#define CHATCLIENT_H
#include <QMainWindow>
#include <QTcpSocket>
#include <QHostAddress>
#include <QKeyEvent>
QT_BEGIN_NAMESPACE
namespace Ui { class chatclient; }
QT_END_NAMESPACE
class chatclient : public QMainWindow
{
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();
protected:
//键盘事件
virtual void keyPressEvent(QKeyEvent *event);
private:
Ui::chatclient *ui;
//定义客户端套接字指针
QTcpSocket *socket;
//定义用户名
QString userName;
//定义bool类型数据,表示连接状态
bool *isOK;
};
#endif // CHATCLIENT_H
.cpp
#include "chatclient.h"
#include "ui_chatclient.h"
chatclient::chatclient(QWidget *parent)
: QMainWindow(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信号,在对应槽函数中处理逻辑
}else {
userName = ui->userNameEdit->text();
QString mes = userName + "离开群聊";
socket->write(mes.toLocal8Bit());
//断开服务器
socket->disconnectFromHost();
}
}
//connected信号槽函数,连接服务器
void chatclient::on_connected_slot()
{
//改变将按钮文本
ui->connectBtn->setText("断开连接");
*isOK = true;
userName = ui->userNameEdit->text();
QString mes = userName + "加入群聊";
socket->write(mes.toLocal8Bit()); //告诉服务器我来了
ui->sendBtn->setEnabled(true);
ui->userNameEdit->setEnabled(false);
ui->ipEdit->setEnabled(false);
ui->portEdit->setEnabled(false);
ui->connectBtn->setStyleSheet(QString("background-color: rgb(255,0,0);border-radius:25px"));
}
//disconnected信号槽函数,断开服务器
void chatclient::on_disconnected_slot()
{
ui->listWidget->addItem("与服务器断开连接");
//改变将按钮文本
ui->connectBtn->setText("连接服务器");
*isOK = false;
ui->sendBtn->setEnabled(false);
ui->userNameEdit->setEnabled(true);
ui->ipEdit->setEnabled(true);
ui->portEdit->setEnabled(true);
ui->connectBtn->setStyleSheet(QString("background-color: rgb(0,170,255);border-radius:25px"));
}
//readyRead信号槽函数,接收消息
void chatclient::on_readyRead_slot()
{
//获取套接字中的数据
QString mes = QString::fromLocal8Bit(socket->readAll());
//将数据显示在list widget中
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();
}
void chatclient::keyPressEvent(QKeyEvent *event)
{
if(event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return);
{
on_sendBtn_clicked();
}
}