前言: Qt网络模块提供了用于编写TCP/IP客户端和服务器端程序的各种类,如用于TCP通信的QTcpSocket和QTcpServer,用于UDP通信的QUdpSocket,还有用于实现HTTP、FTP等普通网络协议的高级类,如:QNetworkReauest、QNetworkReply等。Qt模块还提供用于网络代理、网络承载管理的类,提供基于安全套接字层(Secure Sockets Layer,SSL)协议的安全网络通信的类。
1、浅谈网络编程
网络编程有TCP(transmission control protocol,被大多数Internet网络协议如:HTTP和FTP用于数据传输的低级网络协议) 和 UDP(user datagram protocol,用户数据报协议)。
区别 | |
---|---|
是否连接 | TCP面向连接 ;UDP面向非连接 |
传输可靠性 | TCP可靠 ;UDP不可靠 |
应用场合 | TCP适用于少量数据(如:传输文件) ;UDP可传输大量数据(如:传输视频语音) |
TCP分为服务器和客户端,服务器这两个类都会用到;客户端只用到了QTcpSocket。
2、关于客户端的网络编程
服务器部分:
**第一部分:ui界面的设计**
(1)新建一个QT工程(路径为:D:\qt\qt_demo\network\TcpServer)
(2)在“帮助”–“索引”下面查看QTcpServer的相关信息;在工程文件中加入类QTcpServer
所需要的模块以及在头文件里面包含所需要的头文件;类QTcpSocket同理。
QT += core gui network
添加完之后,编译一下,看有无问题。通过这些天的学习,对于如何创建一个QT工程已经很了解和熟悉了。就是要规范和小心步骤,可以在操作的过程中做完一步、两步的,就执行一下编译,以防最后出现问题排错困难。
ok,编译无问题,继续往下走。
(3)跟设计“上位机串口助手”的思路一样,同样也需要设计ui界面,那么久根据之前的经验,先设计图像界面,在图像界面设计好之后,再设计逻辑功能。
TCP服务器需要有一个接收框(Plain Text Edit控件),一个发送框(Line Edit),几个按钮(pushbutton),服务器是不需要设置IP的,但是需要设置端口号(Line Edit),(Label),再使用(Group Box)控件将发送窗口以及接收窗口框起来,使得界面美观一些。
放置好控件之后,给ui界面的控件布局,红色框里的选择水平布局,黄色框里的选择垂直布局,整体再进行栅格布局。
编译运行之后,发现端口号的框框有点大了,给它修正一下,在"端口号"的Label控件后面放置一个水平“弹簧”控件即可。此外,接收框需要设置成“只读”的。调整过后,编译运行,结果如下:
ui界面设计好啦,接下来开始实现它的逻辑功能。
第二部分:实现逻辑功能
在写逻辑代码之前,需要给控件改名字。这个习惯是必须要培养的,不然在代码里出了乱子不好整了。
服务器要监听所有人发来的消息,监听要用到 QTcpServer类的public里面的listen
在程序编写中,还需要关联readyread信号
写完打开服务器、关闭服务器以及发送按钮的功能之后,编译一下,看是否能运行成功。但是我们不知道写的tcp服务器有没有问题,是否可以使用。有两种办法可以验证,一种是将客户端给写完,验证一下服务器是否有问题,同时也将客户端就给验证了,但是如果等到这时候再去验证的话,就无法确定到底客户端还是服务器那里出现了问题。还有一种办法是在网上找一个网络调试助手,用调试助手作客户端,然后用写的程序作服务器,看一下是否能互相通信。
客户端部分:
客户端只用到TcpSocket就可以啦。
第一个工作:ui界面的设计
首先要包含头文件以及network模块;
其次设计ui界面。同样地,也是需要有一个接收框,一个发送框,设置ip的框(因为客户端需要设置ip—Line Edit),端口号,三个按钮。放置好组件之后,给组件布局并编译运行,结果如下图所示:
接着修改组件的名称,在后续逻辑功能实现的时候会便利。
第二个工作:实现逻辑功能
再下一步,关联信号和槽。对于打开客户端来说,选择“自动关联”;对于“关闭客户端”以及“发送”来说,仍然选择自动关联。widget.cpp的代码如下:
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
tcpSocket = new QTcpSocket(this);
}
void Widget::connected_Slot()
{
//在这个槽函数里面关联readyread
connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(readyRead_Slot()));
}
void Widget::readyRead_Slot()
{
//在这个槽函数里面进行一个读操作
ui->recvEdit->appendPlainText(tcpSocket->readAll());
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_openBt_clicked()
{
//打开客户端:自动连接槽函数;令其连接服务器
tcpSocket->connectToHost(ui->IPEdit->text(),ui->portEdit->text().toUInt()); //转成无符号的整型
//连接成功之后,会发出连接成功的(connected)信号,然后用connect来关联一下就可以
connect(tcpSocket,SIGNAL(connected()),this,SLOT(connected_Slot()));
//然后去头文件里面声明一下槽函数
}
void Widget::on_closeBt_clicked()
{
tcpSocket->close();
}
void Widget::on_sendBt_clicked()
{
tcpSocket->write(ui->sendEdit->text().toLocal8Bit().data());
}
编译运行,无问题。
然后需要检查一下写的客户端和服务器能否正常运行。在界面上打开服务器的代码,编译一下“服务器”。然后再编译一下“客户端”。结果如下图所示:
3、收发功能的测试
在windows下的命令提示符里查看电脑的ip,如下图所示:
端口号一定要设置成一致的,进行测试,看服务器能否和客户端互相之间收发信息。
ok,功能还是可以的。后续需要多回顾整个流程,便于以后开发更多的东西!