QT网络通信编码实现后的整理

  上周在工作中需要编码实现一个测试用的小软件,主要要求如下:

   ①需要有前端界面,可以和用户进行交互;

   ②客户端将数据打包成TCP数据帧并发送给服务端,接收并解析服务端回传的UDP数据帧;

   ③服务器端接收客户端发送的TCP数据帧并解析,根据服务器端界面操作回传不同的UDP数据帧给客户端;

   ④能够实现客户端和服务器端的时间同步,以完成超时未应答提示功能。

   结合功能需求和需要在RedHat、Ubuntu和windows多个平台下运行的可移植性需求,决定采用QT来实现前端界面显示交互功能。经过一周的学习,基本实现了上述功能需求。希望通过这篇随笔来记录自己的学习经历并归纳总结学习到的一些零碎知识点,方便日后查看。编码是通过VS2013+QT5.5(32位版)来完成的

   本篇随笔主要分为三个模块:界面相关内容(QT)整理通信相关内容(Socket)整理以及相应的代码和界面截图

   1、界面相关内容整理

QT5.5在VS2013下的安装就不赘述了,网上很多教程。

安装好之后就要创建自己的项目了,说两个自己在创建项目的时候碰到的问题吧

①创建项目时选择需要的模块,比如说我这里需要的network网络模块,有两种做法:

   第一种做法,也是我在博客中经常看到的做法,就是在项目的.pro文件中添加语句:QT+=network,这种做法适用于使用QT Create软件开发QT程序时使用。

   第二种做法,也是我这里使用的办法,只需在下图界面勾选自己需要的即可。在VS中编译QT程序会让你在创建项目时就选择相应的依赖模块。

项目创建时默认只勾选Core、GUI和Widget这三个模块,查阅帮助文档了解到:

   Core:其他模块使用的核心非图形类。其他所有QT模块都依赖此模块。

   GUI:图形用户界面(GUI)组件的基类。包括OpenGL。Qt GUI模块提供用于窗口系统集成,事件处理,OpenGL和OpenGL ES集成,2D图形,基本成像,字体和文本的类。

   Widget:使用C ++小部件扩展Qt GUI的类。提供了一组用户界面元素来创建经典桌面式的用户界面。像我们在QT Designer中使用的QLable、QTextEdit等窗口小部件都是基于此模块。

                                                                               QT网络通信编码实现后的整理_第1张图片

②下图界面中的类名称也就是后面QT窗口的名字。

                                                                               QT网络通信编码实现后的整理_第2张图片

③QT Design内的标签操作:

以QLineEdit类为例,标签名为lineEdit_test:

   获取标签框内容: lineEdit_test->text();

   修改标签内显示的内容:lineEdit_test->settext(//框里内容);

以QPushButton类为例,标签名为pushbutton_test:

   新增按钮,并给该按钮连接到指定的触发函数:先在QT Design中选择“编辑信号与槽”,选中按钮,配置相应的连接到指定的函数;

                      在.h文件的private slots:下添加私有槽函数的声明,然后在.cpp文件中添加函数的具体实现,即可利用QT的信号与槽机制实现按钮功能。

                                                                              QT网络通信编码实现后的整理_第3张图片

 

2、通信相关内容整理:

   QT中网络通信有两种不同的通信方式:TCP方式和UDP方式。每种方式又会有Server端和Client端。下面简单介绍一下这两种方式的具体通信流程。

   TCP方式,Server端

   ①创建QTcpServer对象;

   ②启动服务器调用成员方法listen(QHostAddress::Any,端口号)监听制定的连接和端口号;

   ③当有客户端连接时发送newConnection()信号,触发槽函数接受连接,得到一个与客户端通信的套接字QTcpSocket;

   ④QTcpSocket发送数据调用成员方法write()

   ⑤当客户端有数据来时,QTcpSocket对象会发送readyread()信号,关联相应的槽函数read()或readall()读取信息;

   ⑥当客户端断开连接时,QTcpSocket对象会发送disconnected()信号,关联相应的槽函数来执行后续操作。

   TCP方式,Client端

   ①创建QTcpSocket对象;

   ②连接到服务器connectToHost(QHostAddress"IP",端口号);

   ③QTcpSocket发送数据调用成员方法write();

   ④当服务器端有数据来时,QTcpSocket对象会发送readyread信息,关联相应的槽函数read()或readall()来接收数据;

   ⑤QTcpSocket调用成员函数close()关闭TCP连接。

注:

一般常用readall()函数接收数据,但在传输数据量很大的情况下readall()函数并一定能一次性读完整,需要分批次读取数据包

read()和readall()的函数原型如下:

QByteArray QIODevice :: read(qint64 maxSize

这是一个过载功能。

从设备读取最多maxSize字节,并返回读取为QByteArray的数据。

此功能无法报告错误; 返回一个空的QByteArray可能意味着当前没有数据可供读取,或者发生了错误

QByteArray QIODevice :: readAll()

从设备读取所有剩余数据,并将其作为字节数组返回。

此功能无法报告错误; 返回一个空的QByteArray可能意味着当前没有数据可供读取,或者发生了错误。

 

UDP通信分为单播、组播和广播这三种通信方式,下面以单播为例,介绍UDP通信流程:

UDP方式,Server端

   ①创建套接字UdpSocket;

   ②调用对象函数bind(),绑定接收的IP地址和端口号;

   ③当数据到来,通过readyread()信号,绑定槽函数readDatagram()来接收数据;

   ④发送数据时,调用writeDatagram()函数发送数据

UDP方式,Send端

   ①创建套接字UdpSocket;

   ②调用成员函数wirteDatagram(),发送数据到指定地址和端口号;

注:

单播、组播和广播的区别只是在发送数据的时候IP地址不同。

rearDatagram()和writeDatagram()的函数原型如下:

qint64 QUdpSocket :: readDatagram( char * data,qint64 maxSize,QHostAddress * address = nullptr,quint16 * port = nullptr)

接收不大于maxSize字节的数据报并将其存储在数据中。发送方的主机地址和端口存储在* address和* port中(除非指针为0)。

成功时返回数据报的大小; 否则返回-1。

如果maxSize太小,则数据报的其余部分将丢失。为避免数据丢失,请在尝试读取之前调用pendingDatagramSize()以确定挂起数据报的大小。如果maxSize为0,则丢弃数据报。

qint64 QUdpSocket :: writeDatagram(const char * data,qint64 size,const QHostAddressaddress,quint16 port

在发送数据报的数据大小的尺寸到主机地址的地址的端口端口。返回成功发送的字节数; 否则返回-1。

数据报总是写成一个块。数据报的最大大小取决于平台,但可以低至8192字节。如果数据报太大,此函数将返回-1,error()将返回DatagramTooLargeError。

通常不会发送大于512字节的数据报,因为即使它们被成功发送,它们也可能在到达其最终目的地之前被IP层分段。

警告:在连接的UDP套接字上调用此函数可能会导致错误并且不会发送任何数据包。如果使用连接的套接字,请使用write()发送数据报。

 

QTcp Socket连接时的一点总结:

   它的大部分功能都是异步工作的,这样可以在一个线程中实现多路TCP连接,节省资源。但在一些情况下需要保证连接的同步,这时可以调用QTcpSocket的waitfor...()系列函数来挂起调用线程,直到发出相应的信号。例如确定断开与服务器的链接:

   m_tcpSocket->disconnectFromHost();

   m_tcpSocket->waitForDisconnected();

wait系列函数主要有:(函数返回值为bool类型)

   waitForConnected()    等待链接建立

   waitForReadyRead()   等待数据到来

   waitForBytesWritten()  等待数据写入socket

   waitForDisconnected() 等待链接断开

   同步套接字通常可以让代码拥有更简单的控制流。waitFor系列函数主要缺点是在函数阻塞时不会处理其他事件。如果在GUI线程中使用,则可能会冻结应用程序的界面。因此,官方文档建议仅在非GUI线程中使用同步套接字。同步使用时,QTcpSocket不需要事件循环。

 

参考资料:

https://blog.csdn.net/qq295456059/article/details/52781726

https://www.cnblogs.com/wurenzhong/p/8018862.html

https://www.cnblogs.com/wurenzhong/p/8030220.html

http://blog.sina.com.cn/s/blog_4888f88101014euy.html#cmt_2022332

转载于:https://www.cnblogs.com/xukai6/p/9628865.html

你可能感兴趣的:(网络,前端,操作系统,ViewUI)