项目介绍
软件界面
gitee界面:
1 tcp网络调试助手
1.1项目概述
- 网络相关的一些基础概念
- 学习qtcpserver
- 学习qtcpclient
- 学习textedit特定位置输入文字颜色
- 学习网络通信相关知识点
- 复习巩固之前ui控件
- 程序运行如下图所示
1.2开发流程
1.3 qttcp服务器的关键流程
工程建立,需要在.pro加入网络权限
qt network+= core gui
创建一个基于"qtcpserver"的服务端涉及以下关键步骤:
1.创建并初始化 qtcpserver 实例
实例化 qtcpserver。
o:调用"listen,方法在特定端口监听传入的连接。
2.处理新连接:
为 newconnection"信号连接一个槽函数。在槽函数中,使用"nextpendingconnection 获取'qfcpsocket,以与客户端通信。
3.读取和发送数据:
通过连接"qtcpsocket 的:readyread 信号来读取来自客户端的数据。'使用write"方法发送数据回客户端。
4.关闭连接:
适当的时候关闭 qtcpsocket 。
class myserver : public qobject { q_object public: myserver() { qtcpserver *server = new qtcpserver(this); connect(server, &qtcpserver::newconnection, this, &myserver::onnewconnection); server->listen(qhostaddress::any, 1234); } private slots: void onnewconnection() { qtcpsocket *clientsocket = server->nextpendingconnection(); connect(clientsocket, &qtcpsocket::readyread, this, &myserver::onreadyread); // ... } void onreadyread() { qtcpsocket *clientsocket = qobject_cast<qtcpsocket *>(sender()); // 读取数据 qbytearray data = clientsocket->readall(); // 处理数据 // ... } };
确保在使用 qtcpserver 和 qtcpsocket 时妥善处理网络错误和异常情况。
1.4 qttcp客户端的关键流程
创建一个基于 qtcpsocket 的qt客户端涉及以下步骤:
1. 创建 qtcpsocket 实例:
实例化 qtcpsocket 。
2. 连接到服务器:
使用 connecttohost 方法连接到服务器的ip地址和端口。
3. 发送数据到服务器:
使用 write 方法发送数据。
4. 接收来自服务器的数据:
为 readyread 信号连接一个槽函数来接收数据。
5. 关闭连接:
关闭 qtcpsocket 连接。
示例代码如下:
class myclient : public qobject { q_object public: myclient() { qtcpsocket *socket = new qtcpsocket(this); connect(socket, &qtcpsocket::readyread, this, &myclient::onreadyread); socket->connecttohost("server_address", 1234); } private slots: void onreadyread() { qtcpsocket *socket = qobject_cast<qtcpsocket *>(sender()); qbytearray data = socket->readall(); // 处理接收到的数据 // ... } };
2 tcp协议
以下内容自省阅读和消化,主要在面试之前类似八股文问答,实际编程我们不需要关系这么多,qtcpsocket类底下的api已经做好所有的封装。
tcp(传输控制协议)是一种广泛使用的网络通信协议,设计用于在网络中的计算机之间可靠地传输数据。它是互联网协议套件的核心部分,通常与ip(互联网协议)一起使用,合称为tcp/ip。以下是tcp协议的一些基本特点:
1. 面向连接:在数据传输之前,tcp 需要在发送方和接收方之间建立一个连接。这包括三次握手过程,确保两端都准备好进行数据传输。
2. 可靠传输:tcp 提供可靠的数据传输服务,这意味着它保证数据包准确无误地到达目的地。如果发生数据丢失或错误,tcp 会重新发送数据包。
3. 顺序控制:tcp 保证数据包的传输顺序。即使数据包在网络中的传输顺序被打乱,接收方也能按照正确的顺序重组这些数据。
4. 流量控制:tcp 使用窗口机制来控制发送方的数据传输速率,以防止网络过载。这有助于防止接收方被发送方发送的数据所淹没。
5. 拥塞控制:tcp 还包括拥塞控制机制,用来检测并防止网络拥塞。当网络拥塞发生时,tcp 会减少其数据传输速率。
6. 数据分段:大块的数据在发送前会被分割成更小的段,以便于传输。这些段会被独立发送并在接收端重新组装。
7. 确认和重传:接收方对成功接收的数据包发送确认(ack)信号。如果发送方没有收到确认,它会重传丢失的数据包。
8. 终止连接:数据传输完成后,tcp 连接需要被正常关闭,这通常涉及到四次挥手过程。
tcp 适用于需要高可靠性的应用,如网页浏览、文件传输、电子邮件等。然而,由于它的这些特性,tcp在处理速度上可能不如其他协议(如udp)那么快速。
tcp协议中的三次握手和四次挥手是建立和终止连接的重要过程。下面是它们的简要描述:
三次握手(建立连接)
三次握手的主要目的是在两台设备之间建立一个可靠的连接。它包括以下步骤:
1. syn:客户端向服务器发送一个syn(同步序列编号)报文来开始一个新的连接。此时,客户端进
入syn-sent状态。
2. syn-ack:服务器接收到syn报文后,回复一个syn-ack(同步和确认)报文。此时服务器进入
syn-received状态。
3. ack:客户端接收到syn-ack后,发送一个ack(确认)报文作为回应,并进入established(已
建立)状态。服务器在收到这个ack报文后,也进入established状态。这标志着连接已经建立。
四次挥手(断开连接)
四次挥手的目的是终止已经建立的连接。这个过程包括以下步骤:
1. fin:当通信的一方完成数据发送任务后,它会发送一个fin(结束)报文来关闭连接。发送完fin报文后,该方进入fin-wait-1状态。
2. ack:另一方接收到fin报文后,发送一个ack报文作为回应,并进入close-wait状态。发送fin报文的一方在收到ack后,进入fin-wait-2状态。
3. fin:在等待一段时间并完成所有数据的发送后,close-wait状态的一方也发送一个fin报文来请求关闭连接。
4. ack:最初发送fin报文的一方在收到这个fin报文后,发送一个ack报文作为最后的确认,并进入time-wait状态。经过一段时间后,确保对方接收到了最后的ack报文,该方最终关闭连接。
在这两个过程中,三次握手主要确保双方都准备好进行通信,而四次挥手则确保双方都已经完成通信并同意关闭连接。
3 socket
socket 不是一个协议,而是一种编程接口(api)或机制,用于在网络中实现通信。socket 通常在应用
层和传输层之间提供一个端点,使得应用程序可以通过网络发送和接收数据。它支持多种协议,主要是
tcp 和 udp。 以下是 socket 的一些基本特点:
类型:有两种主要类型的 sockets —— tcp socket(面向连接,可靠)和 udp socket(无连接,不可靠)。
应用:在各种网络应用中广泛使用,如网页服务器、聊天应用、在线游戏等。
编程语言支持:大多数现代编程语言如 python, java, c++, 等都提供 socket 编程的支持。
功能:提供了创建网络连接、监听传入的连接、发送和接收数据等功能。
qt: 在qt组件中,qtcpsocket用来管理和实现tcp socket通信,qudpsocket用来管理和实现
udp socket通信
总之,socket 是实现网络通信的基础工具之一,它抽象化了网络层的复杂性,为开发者提供了一种相对 简单的方式来建立和管理网络连接。
4 创建tcp服务端的核心代码
主要步骤如下:
1. 创建 qtcpserver 实例:启动服务器并开始监听指定端口。
2. 监听连接请求:调用 listen() 方法使服务器监听特定的 ip 地址和端口。
3. 接受连接:当客户端尝试连接时, qtcpserver 产生一个信号。你需要实现一个槽(slot)来响应这个信号,并接受连接。
4. 处理客户端连接:每个连接的客户端都关联一个 qtcpsocket 对象,用于数据交换。
示例代码
#include <qtcpserver> #include <qtcpsocket> #include <qcoreapplication> #include <qdebug> int main(int argc, char *argv[]) { qcoreapplication a(argc, argv); qtcpserver server; // 监听端口 if (!server.listen(qhostaddress::any, 12345)) { qdebug() << "server could not start"; return -1; } qdebug() << "server started!"; // 当有新连接时,执行相应的操作 qobject::connect(&server, &qtcpserver::newconnection, [&]() { qtcpsocket *client = server.nextpendingconnection(); qobject::connect(client, &qtcpsocket::readyread, [client]() { qbytearray data = client->readall(); qdebug() << "received data:" << data; client->write("hello, client!"); }); qobject::connect(client, &qtcpsocket::disconnected, client, &qtcpsocket::deletelater); }); return a.exec(); }
代码解释
1. 创建 qtcpserver 对象:在主函数中,直接创建了一个 qtcpserver 对象。
2. 监听端口:使用 listen() 方法监听所有接口上的 12345 端口。
3. 处理新连接:通过连接 newconnection 信号,当有新客户端连接时,会调用相应的槽函数。
4. 读取数据:为每个连接的客户端创建 qtcpsocket 对象,并连接 readyread 信号以接收数据。
5. 发送数据:向客户端发送响应消息。
6. 客户端断开连接时的处理:使用 disconnected 信号确保客户端在断开连接时被适当地清理。
这个代码示例展示了如何使用 qtcpserver 创建一个基本的 tcp 服务器,而无需通过继承来扩展类。这 种方式通常更简单,适用于不需要复杂处理的基本应用场景。
5 创建tcp客户端的核心代码
为了使客户端代码更具模块化和响应性,可以使用 qt 的信号与槽机制。这种方法允许客户端以事件驱动 的方式响应网络事件,如连接建立、数据接收等。下面是一个使用信号与槽的 tcp 客户端示例。
示例代码
#include <qtcpsocket> #include <qcoreapplication> #include <qdebug> class tcpclient : public qobject { q_object public: tcpclient(const qstring &host, quint16 port) { connect(&socket, &qtcpsocket::connected, this, &tcpclient::onconnected); connect(&socket, &qtcpsocket::readyread, this, &tcpclient::onreadyread); socket.connecttohost(host, port); } private slots: void onconnected() { qdebug() << "connected to server!"; socket.write("hello, server!"); } void onreadyread() { qbytearray data = socket.readall(); qdebug() << "server said:" << data; socket.disconnectfromhost(); } private: qtcpsocket socket; }; int main(int argc, char *argv[]) { qcoreapplication a(argc, argv); tcpclient client("localhost", 12345); return a.exec(); } #include "main.moc"
代码解释
1. 创建 tcpclient 类:这个类继承自 qobject ,允许使用信号与槽机制。
2. 连接信号和槽:在构造函数中,将 qtcpsocket 的 connected 和 readyread 信号分别连接到onconnected 和 onreadyread 槽。
3. 连接到服务器:使用 connecttohost() 方法开始连接过程。
4. 处理连接建立:一旦连接建立, onconnected 槽被触发,客户端向服务器发送一条消息。
5. 接收数据:当数据可读时, onreadyread 槽被触发,客户端读取并打印来自服务器的数据。
6. 断开连接:在接收数据后,客户端断开与服务器的连接。
这个客户端示例展示了如何使用 qt 的信号与槽机制来处理 tcp 连接。这种方式使得代码更加清晰,易于维护,并且能更好地处理异步事件。
6 tcp服务端项目开发
核心代码
// 包含主窗口和用户界面定义 #include "mainwindow.h" #include "ui_mainwindow.h" // 主窗口构造函数 mainwindow::mainwindow(qwidget *parent) : qmainwindow(parent) , ui(new ui::mainwindow) { // 初始化用户界面 ui->setupui(this); // 设置主窗口中心部件的布局 ui->centralwidget->setlayout(ui->verticallayout_2); // 设置主窗口标题 this->setwindowtitle("网络调试助手服务端-上官qt案例"); cursor = ui->textbrowserrev->textcursor(); // 获取文本浏览器的文本光标 // 初始时禁用“停止监听”按钮 ui->pushbuttonlistenstop->setenabled(false); // 创建新的 tcp 服务器实例 tcpserver = new qtcpserver(this); // 将新连接信号连接到处理新连接的槽函数 connect(tcpserver, signal(newconnection()), this, slot(mnewconnectionhandler())); // 获取系统上所有网络接口,并将 ipv4 地址添加到下拉列表中 qlist<qnetworkinterface> interfaces = qnetworkinterface::allinterfaces(); for (const qnetworkinterface &interface : interfaces) { for (const qnetworkaddressentry &entry : interface.addressentries()) { if (entry.ip().protocol() == qabstractsocket::ipv4protocol) { ui->comboboxipaddr->additem(entry.ip().tostring()); } } } } // 主窗口析构函数 mainwindow::~mainwindow() { // 释放用户界面资源 delete ui; } // “开始监听”按钮的点击事件处理函数 void mainwindow::on_pushbuttonlisten_clicked() { // 侦听指定 ip 地址和端口 tcpserver->listen(qhostaddress(ui->comboboxipaddr->currenttext()), ui->lineeditport->text().toint()); // 更新按钮状态 ui->pushbuttonlisten->setenabled(false); ui->pushbuttonlistenstop->setenabled(true); } // 新 tcp 连接的处理函数 void mainwindow::mnewconnectionhandler() { // 获取下一个待处理的连接 qtcpsocket *tmpsocket = tcpserver->nextpendingconnection(); // 向文本浏览器中添加客户端信息 ui->textbrowserrev->append("服务器: 客户端ip地址是:"+ tmpsocket- >peeraddress().tostring() +" 客户端端口号是: "+qstring::number(tmpsocket- >peerport())+"\n"); // 连接套接字的状态变化和数据接收信号到相应槽函数 connect(tmpsocket, signal(statechanged(qabstractsocket::socketstate)), this, slot(mstatechanged(qabstractsocket::socketstate))); connect(tmpsocket, signal(readyread()), this, slot(mreaddata())); } // 套接字状态改变时的槽函数 void mainwindow::mstatechanged(qabstractsocket::socketstate state) { // 获取发送信号的套接字对象 qtcpsocket *tmp = (qtcpsocket *)sender(); // 根据套接字的不同状态进行不同处理 switch(state){ case qabstractsocket::unconnectedstate: // 客户端断开连接 ui->textbrowserrev->append("服务器:有客户端断开连接!"); tmp->deletelater(); break; case qabstractsocket::connectedstate: // 客户端连接 ui->textbrowserrev->append("服务器:有新客户端接入!"); break; default: break; } } // “停止监听”按钮的点击事件处理函数 void mainwindow::on_pushbuttonlistenstop_clicked() { // 更新按钮状态 ui->pushbuttonlisten->setenabled(true); ui->pushbuttonlistenstop->setenabled(true); // 停止监听端口 tcpserver->close(); } // 接收到数据时的槽函数 void mainwindow::mreaddata() { // 获取发送信号的套接字对象 qtcpsocket *tmp = (qtcpsocket *)sender(); settextcolor(0,0,0); // 设置文本颜色为红色 cursor.inserttext("客户端:"+ tmp->readall()+"\n"); } // “发送”按钮的点击事件处理函数 void mainwindow::on_pushbuttonsend_clicked() { // 查找所有的子 qtcpsocket 对象 qlist<qtcpsocket*> socketlist = tcpserver->findchildren<qtcpsocket*>(); // 向每个连接的客户端发送数据 foreach(qtcpsocket *tmp, socketlist){ tmp->write(ui->texteditsnd->toplaintext().toutf8()); settextcolor(255,0,0); // 设置文本颜色为红色 cursor.inserttext("服务端:"+ui->texteditsnd- >toplaintext().toutf8()+"\n"); }; } // 设置文本颜色的函数 void mainwindow::settextcolor(int r, int g, int b) { qtextcharformat textformat; textformat.setforeground(qbrush(qcolor(r, g, b))); // 根据提供的 rgb 值设置颜色 // 应用格式到光标 cursor.setcharformat(textformat); }
到此这篇关于基于qt编写一个网络调试助手的文章就介绍到这了,更多相关qt网络调试内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!