当前位置: 首页 > news >正文

QT(c++)开发自学笔记:2.TCP/IP

一、下载网络调试助手

        下载连接:通过网盘分享的文件:网络调试助手.exe
链接: https://pan.baidu.com/s/1A-aQ9oLb3aGdxDT8bl6qjw?pwd=nf1z 提取码: nf1z

        就一个.exe,点两次打开两个,两个配置:

 设置一个调试助手为 TCP 服务器

  1. 打开第一个网络调试助手,选择 TCP Server 模式。
  2. 配置服务器参数
    • 本地 IP 地址:选择本机 IP(通常为 127.0.0.1 用于本地测试,或局域网 IP 如 192.168.x.x)。
    • 监听端口:设置一个端口号(如 8888),确保该端口未被其他程序占用。
    • 启动服务器:点击“启动”或“监听”按钮,调试助手进入监听状态,等待客户端连接。
  3. 记录服务器信息:记下服务器的 IP 地址和端口号,用于客户端配置。

设置另一个调试助手为 TCP 客户端

  1. 打开第二个网络调试助手,选择 TCP Client 模式。
  2. 配置客户端参数
    • 远程主机 IP:输入服务器的 IP 地址(与服务器端一致,如 127.0.0.1:8888 或局域网 IP)。
    • 远程端口:输入服务器监听的端口号(如 8888)。
    • 连接服务器:点击“连接”按钮,客户端会尝试连接到服务器。
  3. 确认连接状态:连接成功后,服务器端会显示客户端已连接。

        然后互相发个什么能接收就行

二、PyQt实现

        再用PyQt实现并验证功能,充当TCP Client

        PyQt代码如下:

import sys
import socket
import threading
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QLineEdit, QPushButton, QTextEdit, QCheckBox
from PyQt5.QtCore import pyqtSignal, QObjectclass Communicate(QObject):# 自定义信号,用于线程和主界面通信data_received = pyqtSignal(str)status_updated = pyqtSignal(str)class TCPClientWindow(QMainWindow):def __init__(self):super().__init__()self.setWindowTitle("PyQt TCP Client")self.resize(600, 400)# 初始化通信对象self.comm = Communicate()self.comm.data_received.connect(self.update_display)self.comm.status_updated.connect(self.update_status)# 初始化 socketself.client_socket = Noneself.running = False# 创建界面self.init_ui()def init_ui(self):# 主布局main_widget = QWidget()self.setCentralWidget(main_widget)layout = QVBoxLayout(main_widget)# IP 和端口输入ip_port_layout = QHBoxLayout()self.ip_input = QLineEdit("127.0.0.1")self.port_input = QLineEdit("8888")ip_port_layout.addWidget(QLineEdit("IP:"))ip_port_layout.addWidget(self.ip_input)ip_port_layout.addWidget(QLineEdit("Port:"))ip_port_layout.addWidget(self.port_input)layout.addLayout(ip_port_layout)# 连接、断开、清空按钮button_layout = QHBoxLayout()self.connect_btn = QPushButton("Connect")self.disconnect_btn = QPushButton("Disconnect")self.clear_btn = QPushButton("Clear Log")self.connect_btn.clicked.connect(self.connect_to_server)self.disconnect_btn.clicked.connect(self.disconnect)self.clear_btn.clicked.connect(self.clear_log)self.disconnect_btn.setEnabled(False)button_layout.addWidget(self.connect_btn)button_layout.addWidget(self.disconnect_btn)button_layout.addWidget(self.clear_btn)layout.addLayout(button_layout)# 接收数据区域self.display = QTextEdit()self.display.setReadOnly(True)layout.addWidget(self.display)# 发送数据区域send_layout = QHBoxLayout()self.send_input = QLineEdit()self.send_btn = QPushButton("Send")self.hex_check = QCheckBox("Hex Mode")self.send_btn.clicked.connect(self.send_data)send_layout.addWidget(self.send_input)send_layout.addWidget(self.send_btn)send_layout.addWidget(self.hex_check)layout.addLayout(send_layout)def connect_to_server(self):ip = self.ip_input.text()try:port = int(self.port_input.text())except ValueError:self.comm.status_updated.emit("Invalid port number!")returntry:self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)self.client_socket.connect((ip, port))self.running = Trueself.comm.status_updated.emit(f"Connected to {ip}:{port}")self.connect_btn.setEnabled(False)self.disconnect_btn.setEnabled(True)# 启动接收线程threading.Thread(target=self.receive_data, daemon=True).start()except Exception as e:self.comm.status_updated.emit(f"Connection failed: {str(e)}")def disconnect(self):self.running = Falseif self.client_socket:self.client_socket.close()self.client_socket = Noneself.comm.status_updated.emit("Disconnected")self.connect_btn.setEnabled(True)self.disconnect_btn.setEnabled(False)def receive_data(self):while self.running:try:data = self.client_socket.recv(1024)if not data:self.comm.status_updated.emit("Server closed connection")self.disconnect()breakif self.hex_check.isChecked():# 十六进制显示data_str = data.hex()else:# 文本显示(假设 UTF-8 编码)data_str = data.decode('utf-8', errors='ignore')self.comm.data_received.emit(data_str)except Exception as e:if self.running:self.comm.status_updated.emit(f"Receive error: {str(e)}")self.disconnect()breakdef send_data(self):if not self.client_socket or not self.running:self.comm.status_updated.emit("Not connected to server!")returndata = self.send_input.text()try:if self.hex_check.isChecked():# 发送十六进制数据data_bytes = bytes.fromhex(data)else:# 发送文本数据data_bytes = data.encode('utf-8')self.client_socket.send(data_bytes)self.comm.data_received.emit(f"Sent: {data}")except Exception as e:self.comm.status_updated.emit(f"Send error: {str(e)}")def update_display(self, data):self.display.append(data)def update_status(self, status):self.display.append(f"[Status] {status}")def clear_log(self):self.display.clear()def closeEvent(self, event):self.disconnect()event.accept()if __name__ == '__main__':app = QApplication(sys.argv)window = TCPClientWindow()window.show()sys.exit(app.exec_())

  三、C++实现(进入正题)

        因为毕竟是学习C++,下面就一步步的实现,实现网络调试助手与C++版的QT上位机通讯。

        main.cpp代码如下:

#include "dialog.h"
#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);Dialog w;w.show();return a.exec();
}

        dialog.cpp如下:

#include "dialog.h"
#include "ui_dialog.h"
#include <QMessageBox>
#include <QDebug>Dialog::Dialog(QWidget *parent): QDialog(parent), ui(new Ui::Dialog), tcpSocket(nullptr)
{ui->setupUi(this);initUI();initSocket();
}Dialog::~Dialog()
{if(tcpSocket) {tcpSocket->disconnectFromHost();delete tcpSocket;}delete ui;
}void Dialog::initUI()
{// 设置界面默认状态ui->connectBtn->setText("连接");ui->sendBtn->setEnabled(false);ui->ipEdit->setText("127.0.0.1");ui->portEdit->setText("8080");ui->receiveText->setReadOnly(true);
}void Dialog::initSocket()
{tcpSocket = new QTcpSocket(this);// 连接信号槽connect(tcpSocket, &QTcpSocket::connected,this, &Dialog::on_socket_connected);connect(tcpSocket, &QTcpSocket::disconnected,this, &Dialog::on_socket_disconnected);connect(tcpSocket, &QTcpSocket::readyRead,this, &Dialog::on_socket_readyRead);// 修改为使用 errorOccurred 信号connect(tcpSocket, &QTcpSocket::errorOccurred,this, &Dialog::on_socket_error);
}void Dialog::on_connectBtn_clicked()
{if(!tcpSocket->isOpen()) {// 连接服务器QString ip = ui->ipEdit->text();quint16 port = ui->portEdit->text().toUInt();tcpSocket->connectToHost(QHostAddress(ip), port);ui->connectBtn->setText("连接中...");ui->connectBtn->setEnabled(false);} else {// 断开连接tcpSocket->disconnectFromHost();ui->connectBtn->setText("断开中...");}
}void Dialog::on_sendBtn_clicked()
{if(tcpSocket && tcpSocket->state() == QAbstractSocket::ConnectedState) {QString message = ui->sendText->toPlainText();if(!message.isEmpty()) {tcpSocket->write(message.toUtf8());tcpSocket->flush(); // 立即发送// 添加到发送记录ui->receiveText->append("[发送] " + message);ui->sendText->clear();}} else {QMessageBox::warning(this, "警告", "请先连接服务器!");}
}void Dialog::on_socket_connected()
{ui->connectBtn->setText("断开");ui->connectBtn->setEnabled(true);ui->sendBtn->setEnabled(true);ui->statusLabel->setText("状态: 已连接");ui->receiveText->append("[系统] 连接成功!");qDebug() << "TCP连接成功";
}void Dialog::on_socket_disconnected()
{ui->connectBtn->setText("连接");ui->connectBtn->setEnabled(true);ui->sendBtn->setEnabled(false);ui->statusLabel->setText("状态: 已断开");ui->receiveText->append("[系统] 连接已断开");qDebug() << "TCP连接断开";
}void Dialog::on_socket_readyRead()
{QByteArray data = tcpSocket->readAll();QString message = QString::fromUtf8(data);ui->receiveText->append("[接收] " + message);qDebug() << "接收数据:" << message;
}void Dialog::on_socket_error(QAbstractSocket::SocketError socketError)
{QString errorStr;switch(socketError) {case QAbstractSocket::RemoteHostClosedError:errorStr = "服务器关闭连接";break;case QAbstractSocket::HostNotFoundError:errorStr = "服务器地址错误";break;case QAbstractSocket::ConnectionRefusedError:errorStr = "连接被拒绝";break;default:errorStr = tcpSocket->errorString();}ui->connectBtn->setText("连接");ui->connectBtn->setEnabled(true);ui->sendBtn->setEnabled(false);ui->statusLabel->setText("状态: 连接失败");ui->receiveText->append("[错误] " + errorStr);QMessageBox::critical(this, "连接错误", errorStr);qDebug() << "TCP错误:" << errorStr;
}

dialog.h代码如下:

#ifndef DIALOG_H
#define DIALOG_H#include <QDialog>
#include <QTcpSocket>
#include <QHostAddress>QT_BEGIN_NAMESPACE
namespace Ui { class Dialog; }
QT_END_NAMESPACEclass Dialog : public QDialog
{Q_OBJECTpublic:Dialog(QWidget *parent = nullptr);~Dialog();private slots:void on_connectBtn_clicked();void on_sendBtn_clicked();void on_socket_connected();void on_socket_disconnected();void on_socket_readyRead();void on_socket_error(QAbstractSocket::SocketError socketError);private:Ui::Dialog *ui;QTcpSocket *tcpSocket;void initUI();  // 初始化界面void initSocket(); // 初始化Socket
};#endif // DIALOG_H

CMakeLists.txt代码如下:

cmake_minimum_required(VERSION 3.16)project(TCP_IP_Test VERSION 0.1 LANGUAGES CXX)set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)# 添加Network组件到find_package中
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets Network LinguistTools)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Network LinguistTools)set(TS_FILES TCP_IP_Test_zh_CN.ts)set(PROJECT_SOURCESmain.cppdialog.cppdialog.hdialog.ui${TS_FILES}
)if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)qt_add_executable(TCP_IP_TestMANUAL_FINALIZATION${PROJECT_SOURCES})qt_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} ${TS_FILES})
else()if(ANDROID)add_library(TCP_IP_Test SHARED${PROJECT_SOURCES})else()add_executable(TCP_IP_Test${PROJECT_SOURCES})endif()qt5_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} ${TS_FILES})
endif()# 添加Network到target_link_libraries
target_link_libraries(TCP_IP_Test PRIVATEQt${QT_VERSION_MAJOR}::WidgetsQt${QT_VERSION_MAJOR}::Network  # 添加这一行
)if(${QT_VERSION} VERSION_LESS 6.1.0)set(BUNDLE_ID_OPTION MACOSX_BUNDLE_GUI_IDENTIFIER com.example.TCP_IP_Test)
endif()
set_target_properties(TCP_IP_Test PROPERTIES${BUNDLE_ID_OPTION}MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}MACOSX_BUNDLE TRUEWIN32_EXECUTABLE TRUE
)include(GNUInstallDirs)
install(TARGETS TCP_IP_TestBUNDLE DESTINATION .LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)if(QT_VERSION_MAJOR EQUAL 6)qt_finalize_executable(TCP_IP_Test)
endif()

在dialog.ui中要添加如下控件:

控件类型对象名称文本/提示
Line EditipEdit127.0.0.1
Line EditportEdit8080
QPushButtonconnectBtn连接
Text EditsendText发送消息...
QPushButtonsendBtn发送
Text EditreceiveText(只读)
LabelstatusLabel状态: 未连接

运行结果如下:

http://www.dtcms.com/a/490407.html

相关文章:

  • C语言基础语法进阶
  • 池州网站建设公司好的网站你知道
  • 从零起步学习MySQL || 第五章:select语句的执行过程是怎么样的?(结合源码深度解析)
  • 专业的家居网站建设网站单页支付宝支付怎么做的
  • CC10-判断链表中是否有环
  • 【ZEGO即构开发者日报】谷歌推出新款视频生成模型 Veo 3.1;腾讯开源通用文本表示模型Youtu-Embedding;AI 陪伴赛道观察……
  • [Sora] 视频自动编码器(VAE) | `encode_``decode`
  • 算法沉淀第四天(Winner)
  • 西藏地图飞线html
  • 网站建设与管理课程代码做徽章标牌的企业网站
  • selenium实现自动化脚本的常用函数
  • 大语言模型,一个巨大的矩阵
  • 衡阳营养师报考网站大宗贸易交易平台
  • Azure API Management 负载均衡与故障转移策略完整指南
  • TI CCS软件安装
  • 内存映射文件
  • 网站开发开发语言企业网站做seo的优势
  • 资料片:R语言中常见的英文术语及其含义
  • 企业出海的挑战与应对方案
  • 架构术语:什么是东西流量和南北流量
  • 电子电器架构——车载网关转发buffer心得汇总
  • (Python)终端着色进阶:256色基础及色码效果展示
  • 《R for Data Science (2e)》免费中文翻译 (第10章) --- Exploratory data
  • 简述对网站进行评析的几个方面.wordpress 内涵
  • Python自动化从入门到实战(23):Python打地鼠游戏开发
  • (论文速读)ECLIPSE:突破性的轻量级文本到图像生成技术
  • dede 网站入侵新媒体h5是什么
  • 嵌入式系统守护者:复位IC详解与选型指南
  • 实战指南:用Cliproxy实现Reddit多账号安全运营的完整方案
  • Ovi-音视频生成模型