目录
一、编写思路
1、服务器
(1)总体思路widget.c(主线程)
(2)详细流程widget.c(主线程)
(1)总体思路chat_thread.c(处理聊天逻辑线程)
(2)详细流程chat_thread.h(处理聊天逻辑线程)
2、客户端
(1)总体思路widget.c(主线程)
(2)详细思路widget.c(主线程)
(1)总体思路chat_thread.c(处理聊天逻辑线程)
(2)详细流程chat_thread.c(处理聊天逻辑线程)
二、实现效果
1、服务器
2、客户端
完整代码请到指定链接下载:Qt网络编程-Tcp多线程并发服务器和客户端通信: 【Qt网络编程】Tcp多线程并发服务器和客户端通信
一、编写思路
1、服务器
(1)总体思路widget.c(主线程)
初始化界面
创建窗口、输入框、按钮等基本UI元素。
创建服务器对象
实现 My_tcp_server 并监听客户端连接。
处理新客户端连接
当有新客户端连接时,创建新的 Chat_thread 线程来处理通信。
绑定信号槽
确保主线程与客户端处理线程间的信号槽连接,使用 Qt::QueuedConnection 处理跨线程通信。
处理消息传递
接收和发送消息,并在界面上更新显示。
服务器启动与关闭
通过按钮控制服务器的启动和关闭,管理所有客户端线程的安全退出。
(2)详细流程widget.c(主线程)
创建 Qt 界面及设置窗口属性: 首先通过 ui->setupUi(this); 来初始化用户界面,并设置窗口标题、大小等基本属性。这是 Qt 项目的常见步骤,通过 .ui 文件生成的类进行界面管理。
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget) // 初始化UI对象
{
ui->setupUi(this); // 设置UI界面
this->setWindowTitle(\”–服务器–\”); // 设置窗口标题
this->resize(1024, 960); // 设置窗口大小
ui->le_ip->setText(\”127.0.0.1\”);
ui->le_port->setText(\”9999\”);
}
初始化服务器对象 My_tcp_server 并处理客户端连接:
-
创建 tcp_server 对象以处理客户端的连接。
-
使用 connect 函数连接 tcp_server 的 new_descriptor 信号和匿名槽函数,确保一旦有新客户端连接,便创建一个 Chat_thread 来处理该客户端。
this->tcp_server = new My_tcp_server(this);
connect(tcp_server, &My_tcp_server::new_descriptor, this, [=](qintptr socketDescriptor){
QMessageBox::information(this, \”提示\”, \”新的客户端连接!\”, QMessageBox::Ok, QMessageBox::Information);
ui->btn_send->setEnabled(true); // 启用“发送消息”按钮
// 创建新线程处理客户端
Chat_thread *chat_thread = new Chat_thread(socketDescriptor);
chat_thread->moveToThread(chat_thread); // 将线程和对象绑定到同一线程,防止冲突
thread_list.append(chat_thread);
// 启动线程处理客户端通信
chat_thread->start();
});
管理客户端线程 Chat_thread:
-
每当有新客户端连接时,创建一个 Chat_thread 并启动它处理客户端通信。通过 moveToThread 将 Chat_thread 的执行线程与该对象保持一致,避免跨线程冲突。
-
使用 connect 绑定线程中的信号(如连接断开、接收消息)和主界面槽函数,确保客户端状态能够正确显示。
Chat_thread *chat_thread = new Chat_thread(socketDescriptor);
chat_thread->moveToThread(chat_thread); // 将线程与对象绑定在同一线程
thread_list.append(chat_thread);
// 连接信号和槽
connect(chat_thread, &Chat_thread::break_connect, this, [=](){
ui->te_receive->append(currentTime + \”\\n【状态】客户端断开连接…\”);
ui->btn_send->setEnabled(false); // 禁用“发送消息”按钮
});
connect(chat_thread, &Chat_thread::recv_info, this, [=](QString data){
currentTime = QDateTime::currentDateTime().toString(\”yyyy-MM-dd hh:mm:ss\”);
ui->te_receive->append(currentTime + \”form client\\n 【数据】 \” + data); // 在文本框中显示消息
});
chat_thread->start(); // 启动线程
处理启动和关闭服务器的按钮事件:
-
on_btn_connect_clicked() 处理连接按钮点击事件,启动或关闭服务器。
-
启动时,检查 IP 地址和端口的有效性,成功后开始监听客户端连接。
-
关闭服务器时,停止监听,并确保所有已连接客户端线程安全退出。
void Widget::on_btn_connect_clicked()
{
if (!is_server_running)
{
// 启动服务器
QString ip_address = ui->le_ip->text().trimmed();
QString port_text = ui->le_port->text().trimmed();
if (!tcp_server->listen(QHostAddress(ip_address), port_text.toUInt()))
{
QMessageBox::warning(this, \”warning\”, \”服务器监听失败\”);
return;
}
is_server_running = true;
ui->btn_connect->setText(\”关闭服务器\”);
ui->te_receive->append(currentTime + \”\\n【状态】服务器开始监听…\”);
}
else
{
// 停止服务器并关闭所有客户端线程
tcp_server->close();
for (Chat_thread *thread : qAsConst(thread_list))
{
thread->exit();
thread->wait();
thread->deleteLater();
}
thread_list.clear();
is_server_running = false;
ui->btn_connect->setText(\”创建服务器\”);
ui->te_receive->append(currentTime + \”\\n【状态】服务器已停止监听…\”);
}
}
处理发送消息按钮的点击事件:
-
当点击“发送消息”按钮时,触发 send_request 信号,利用信号槽机制将输入的消息发送给客户端。需要确保主线程和子线程的信号槽通信是异步进行的(通过 Qt::QueuedConnection)。
void Widget::on_btn_send_clicked()
{
QString data = ui->te_send->toPlainText().toUtf8();
emit send_request(data); // 发出 send_request 信号
}</
评论前必须登录!
注册