/*client*/
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
, socket(new QTcpSocket(this)) // 给客户端指针实例化空间
{
ui->setupUi(this);
// 初始化界面
ui->text_Edit->setEnabled(false);
ui->send_btn->setEnabled(false);
ui->unconnect_btn->setEnabled(false);
// 如果客户端成功连接服务器 客户端会自动发送一个 connected() 信号
// 将该信号连接到自定义的槽函数 -- 只需要连接1次 --- 连接函数在构造函数中写
connect(socket,&QTcpSocket::connected,this,&Widget::connected_slot);
//
connect(socket, &QTcpSocket::readyRead, this, &Widget::readyRead_slot);
// 如果成功和服务器断开连接 客户端会自动发送一个disconnected信号
// 将该信号连接到自定义的槽函数 只需要连接一次
connect(socket,&QTcpSocket::disconnected,this,&Widget::disconnected_slot);
}
Widget::~Widget()
{
delete ui;
}
// 连接服务器按钮对应的槽函数
void Widget::on_connect_btn_clicked()
{
// 获取ui界面上的ip和端口
QString ip = ui->ip_Edit->text();
quint16 port = ui->port_Edit->text().toUInt(); // 将字符串类型转换成整形
// 让客户端连接服务器
// virtual void connectToHost(const QString &hostName, quint16 port, OpenMode mode = ReadWrite, NetworkLayerProtocol protocol = AnyIPProtocol);
// 参数1 --- 连接服务器的ip
// 参数2 --- 连接服务器的端口
socket->connectToHost(ip,port);
}
// connected()信号 对应的槽函数声明
void Widget::connected_slot()
{
userName = ui->username_Edit->text();
// 告诉服务器,某某客户端进入服务器
QString msg = userName + ":进入聊天室";
// 将信息发送给服务器
socket->write(msg.toLocal8Bit());
ui->text_Edit->setEnabled(true);
ui->send_btn->setEnabled(true);
ui->unconnect_btn->setEnabled(true);
ui->username_Edit->setEnabled(false);
ui->ip_Edit->setEnabled(false);
ui->port_Edit->setEnabled(false);
ui->connect_btn->setEnabled(false);
}
// 发送按钮对应的槽函数
void Widget::on_send_btn_clicked()
{
// 获取ui界面上的文本
QString msg = userName + ":" + ui->text_Edit->text();
// 将listwidget设置成右边显示
QListWidgetItem *p = new QListWidgetItem(msg);
p->setTextAlignment(Qt::AlignRight);
ui->listWidget->addItem(p);
// 将信息发送给服务器
socket->write(msg.toLocal8Bit());
// 清空输入框
ui->text_Edit->clear();
}
void Widget::readyRead_slot()
{
QByteArray msg = socket->readAll();
ui->listWidget->addItem(QString::fromLocal8Bit(msg));
}
// 断开连接按钮 对应的槽函数
void Widget::on_unconnect_btn_clicked()
{
QString msg = userName + ": " + "离开聊天室";
socket->write(msg.toLocal8Bit());
// 断开连接
socket->disconnectFromHost();
}
// disconnected信号 对应的槽函数
void Widget::disconnected_slot()
{
ui->text_Edit->setEnabled(false);
ui->send_btn->setEnabled(false);
ui->unconnect_btn->setEnabled(false);
ui->username_Edit->setEnabled(true);
ui->ip_Edit->setEnabled(true);
ui->port_Edit->setEnabled(true);
ui->connect_btn->setEnabled(true);
}
/*server*/
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
, server(new QTcpServer(this)) // 给服务器指针实例化空间
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
// newConnection 信号 对应的槽函数实现
void Widget::newConnection_slot()
{
// 获取最新连接的客户端的套接字
// virtual QTcpSocket *nextPendingConnection();
QTcpSocket *s = server->nextPendingConnection();
// 将客户端 放入客户端容器中
socketList.push_back(s);
// 此时 客户端与服务器建立连接
// 此时,客户端向服务器发来信息 客户端会发送一个readyread()信号
// 将该信号连接到自定义的槽函数 读取客户端的信息
connect(s,&QTcpSocket::readyRead,this,&Widget::readyRead_slot); // 基于qt5连接
}
// readyRead信号对应的槽函数
void Widget::readyRead_slot() // 读取客户端的数据
{
// 先遍历客户端容器 -- 移除无效客户端
// 容器里的元素个数
for(int i = 0; i < socketList.count(); i++)
{
// 判断客户端和服务器连接的状态
// SocketState state() const;
if(socketList.at(i)->state() == QTcpSocket::UnconnectedState)
{
// 移除无效客户端
socketList.removeAt(i);
}
}
// 遍历客户端容器,判断哪个客户端有数据待读
for(int i = 0; i < socketList.count(); i++)
{
// 判断哪个客户端有数据待读
// qint64 bytesAvailable() const override;
// 返回值是接收数据的字节大小
if(socketList.at(i)->bytesAvailable() != 0)
{
// 读取数据
QByteArray msg = socketList.at(i)->readAll();
// 将读取到的数据,放到ui界面上
ui->listWidget->addItem(QString::fromLocal8Bit(msg));
// 将读取到的数据,广播给所有客户端
for(int j = 0; j < socketList.count(); j++)
{
if(j != i)
{
socketList.at(j)->write(msg);
}
}
}
}
}
// “启动服务器”按钮 对应的槽函数
void Widget::on_Start_btn_clicked()
{
// 获取ui界面上的端口号
quint16 Port = ui->Port_eidt->text().toUInt(); // 将字符串转换成整形
// 启动服务器
// 服务器设置监听
// 监听成功返回ture
if(server->listen(QHostAddress::Any,Port) == true)
{
// 监听成功
QMessageBox::information(this,"","启动server成功");
}
else
{
// 监听失败
QMessageBox::information(this,"","启动server失败");
return;
}
// 监听成功后,继续往下执行
// 此时,有客户端发来连接请求 服务器会自动发送一个 newConnection 信号
// 然后将该信号连接到自定义的槽函数,处理相关的逻辑代码
// 基于qt5连接
connect(server,&QTcpServer::newConnection,this,&Widget::newConnection_slot);
}