服务器
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//给服务器指针实例化对象
server = new QTcpServer(this); //此时就创建了一个服务器
}
Widget::~Widget()
{
delete ui;
}
//启动服务器按钮对应的槽函数
void Widget::on_start_server_btn_clicked()
{
//获取ui界面上的端口号
quint16 port = ui->port_edit->text().toUInt();
//将服务器设置成监听状态
if(server->listen(QHostAddress::Any, port) == 0)
{
QMessageBox::critical(this, "失败", "服务器启动失败");
return;
}
else
{
QMessageBox::information(this, "成功", "服务器启动成功");
}
//此时表明服务器启动成功,并对客户端连接进行监听,如果有客户端向服务器发来连接请求,则该服务器就会自动发射一个newConnection的信号
//我们可以将该信号连接到对应的槽函数中处理相关逻辑
connect(server, &QTcpServer::newConnection, this, &Widget::newConnection_slot);
}
//处理newConnection信号的槽函数的实现
void Widget::newConnection_slot()
{
qDebug() << "有新的客户端发来连接请求";
//获取最新连接的客户端套接字
QTcpSocket *s = server->nextPendingConnection();
//将获取的套接字存放到客户端容器中
clientlist.push_back(s);
//此时客户端就和服务器建立起联系了
//如果该套接字有数据向服务器发送,则该套接字就会自动发射一个readyRead信号
//我们可以将该信号连接到自定义的槽函数中
connect(s, &QTcpSocket::readyRead, this, &Widget::readyRead_slot);
}
//处理readyRead信号的槽函数
void Widget::readyRead_slot()
{
//删除客户端链表中的无效客户端套接字
for (int i = 0; i < clientlist.count(); i++)
{
//判断套接字的状态
if(clientlist[i]->state() == 0)
{
clientlist.removeAt(i); //将下标为i的客户端移除
}
}
//遍历所有客户端,查看是哪个客户端发来数据
for (int i = 0; i < clientlist.count(); i++)
{
//返回当前客户端套接字中的可读数据字节个数
if(clientlist[i]->bytesAvailable() != 0)
{
//读取当前客户端的相关数据
QByteArray msg = clientlist[i]->readAll();
//将数据展示到ui界面上
ui->msg_list->addItem(QString::fromLocal8Bit(msg));
//将接收到的信息,发送给所有客户端
for (int j = 0; j < clientlist.count(); j++)
{
clientlist[j]->write(msg);
}
}
}
}
客户端
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
socket = new QTcpSocket(this);
//如果连接服务器成功,该客户端就会发射一个conneted信号
//我们可以将该信号连接到自定义的槽函数中
//由于该连接只需连接一次
connect(socket, &QTcpSocket::connected, this, &Widget::connected_slot);
//客户端与服务器连接成功后,如果服务器向客户端发送数据,则该客户端会自动发射一个readyRead信号
//我们可以将该信号连接到自定义的槽函数中
connect(socket, &QTcpSocket::readyRead, this, &Widget::readyRead_slot);
ui->disconnect_btn->setEnabled(false);
ui->send_btn->setEnabled(false);
connect(socket, &QTcpSocket::disconnected, this, &Widget::disconnected_slot);
}
Widget::~Widget()
{
delete ui;
}
//连接服务器按钮槽函数
void Widget::on_connect_btn_clicked()
{
//获取ui界面的信息
userName = ui->user_edit->text(); //获取用户名
QString hostName = ui->ip_edit->text(); //主机地址
quint16 port = ui->port_edit->text().toUInt(); //端口号
//调用函数连接到主机
socket->connectToHost(hostName, port);
}
//处理connected信号的槽函数
void Widget::connected_slot()
{
QMessageBox::information(this, "成功", "连接服务器成功");
//向服务器发送消息
QString msg = userName + ":进入聊天室";
socket->write(msg.toLocal8Bit());
ui->disconnect_btn->setEnabled(true);
ui->send_btn->setEnabled(true);
ui->connect_btn->setEnabled(false);
ui->port_edit->setEnabled(false);
ui->ip_edit->setEnabled(false);
ui->user_edit->setEnabled(false);
}
//处理readyRead信号的槽函数
void Widget::readyRead_slot()
{
//读取该客户端中的数据
QByteArray msg = socket->readAll();
//将数据展示在ui界面
ui->msg_list->addItem(QString::fromLocal8Bit(msg));
}
//发送按钮对应的槽函数
void Widget::on_send_btn_clicked()
{
//获取ui界面中编辑的文本内容
QString m = ui->msg_edit->text();
//整合要发送的信息
QString msg = userName + ":" + m;
//将消息发送给服务器
socket->write(msg.toLocal8Bit());
//将消息编辑框中的内容清空
ui->msg_edit->clear();
}
//处理disconnected信号的槽函数
void Widget::disconnected_slot()
{
QMessageBox::information(this, "退出", "断开成功");
ui->disconnect_btn->setEnabled(false);
ui->send_btn->setEnabled(false);
ui->connect_btn->setEnabled(true);
ui->port_edit->setEnabled(true);
ui->ip_edit->setEnabled(true);
ui->user_edit->setEnabled(true);
}
//断开服务器按钮槽函数
void Widget::on_disconnect_btn_clicked()
{
QString msg = userName + ":离开聊天室";
socket->write(msg.toLocal8Bit());
socket->disconnectFromHost();
}
void Widget::keyPressEvent(QKeyEvent *event)
{
qDebug() << "键盘按下了" << event->text() << "键值为:" << event->key();
if(event->text() == "\r")
{
//获取ui界面中编辑的文本内容
QString m = ui->msg_edit->text();
//整合要发送的信息
QString msg = userName + ":" + m;
//将消息发送给服务器
socket->write(msg.toLocal8Bit());
//将消息编辑框中的内容清空
ui->msg_edit->clear();
}
}