您现在的位置是:首页 > 科技前沿
正点原子I.MX6U嵌入式Qt开发指南:第十一章《网络编程》
智慧创新站
2025-01-14【科技前沿】151人已围观
简介第十一章《网络编程》Qt网络模块为我们提供了编写TCP/IP客户端和服务器的类。它提供了较低级别的类,例如代表低级网络概念的QTcpSocket,QTcpServer和QUdpSocket,以及诸如QNetworkRequest,QNetworkReply和QNetworkAccessManager...
第十一章《网络编程》
Qt网络模块为我们提供了编写TCP/IP客户端和服务器的类。它提供了较低级别的类,例如代表低级网络概念的QTcpSocket,QTcpServer和QUdpSocket,以及诸如QNetworkRequest,QNetworkReply和QNetworkAccessManager之类的高级类来执行使用通用协议的网络操作。它还提供了诸如QNetworkConfiguration,QNetworkConfigurationManager和QNetworkSession等类,实现承载管理。
想要在程序中使用Qt网络模块,我们需要在pro项目配置文件里增加下面的一条语句。
QT+=network
11.1获取本机的网络信息为什么先写获取本机网络信息的内容呢?在建立网络通信之前我们至少得获取对方的IP地址。在网络应用中,经常需要用到本机的主机名、IP地址、MAC地址等网络信息,通常通在Windows通过过调出命令行cmd窗口输入ipconfig或者在Linux系统中使用ifconfig命令就可以查看相关信息了,在这里我们利用Qt做出一个可以查询的界面和功能出来,为了后面的网络编程打下一个简单的基础。
Qt提供了QHostInfo和QNetworkInterface类可以用于此类信息查询。更多关于QHostInfo和QNetworkInterface的相关函数可以在Qt的帮助文档中找到。下面我们写代码时会使用到相关的函数,有清楚的注释。
11.1.1应用实例本例目的:了解如何通过QHostInfo和QNetworkInterface类获取本地网络所有接口的信息。
项目文件07_文件第一行添加的代码部分如下。
07_编程后的代码1QT+=coreguinetwork23greaterThan(QT_MAJOR_VERSION,4):QT+=widgets45CONFIG+=c++1167anyQtfeaturethathasbeenmarkeddeprecated(theexac+=QT_DEPRECATED_WARNINGS1213Inordertodoso,+=QT_DISABLE_DEPRECATED_BEFORE=0:=/tmp/${TARGET}/bin27else:unix:!android:=/opt/${TARGET}/bin28!isEmpty():INSTALLS+=target在头文件“”具体代码如下。
第90~123行,是本例最重要的代码。
第93行,通过QHostInfo的localHostName函数获取主机名称。
第97~98行,通过QNetworkInterface::allInterfaces()获取网络接口列表list类存储IP地址子网掩码和广播地址。如果我们用qDebug()函数打印出list,可以发现获取了所有的网络信息。而我们要提取网络里面的网络信息使用QNetworkAddressEntry。
第106~107行,使用QNetworkAddressEntry从interface接口里使用函数addressEntries(),获取所有的条目。就可以使用QNetworkAddressEntry的对象entry获取IP地址子网掩码和广播地址。
第110~118行,因为获取的entries在一个QNetworkInterface下可能有两个IP,分别是ipv4和ipv6。这里使用ip().protocol()来判断协议的类型,只留下ipv4类型的信息。筛选信息在我们写程序常常需要的。
11.1.2程序运行效果11.2TCP通信11.2.1TCP简介TCP协议(TransmissionControlProtocol)全称是传输控制协议是一种面向连接的、可靠的、基于字节流的传输层通信协议。
TCP通信必须先建立TCP连接,通信端分为客户端和服务端。服务端通过监听某个端口来监听是否有客户端连接到来,如果有连接到来,则建立新的socket连接;客户端通过ip和port连接服务端,当成功建立连接之后,就可进行数据的收发了。需要注意的是,在Qt中,Qt把socket当成输入输出流来对待的,数据的收发是通过read()和write()来进行的,需要与我们常见的s()与recv()进行区分。
TCP客户端与服务端通信示意图如下。
11.2.2TCP服务端应用实例本例目的:了解TCP服务端的使用。
项目文件08_文件第一行添加的代码部分如下。
08_编程后的代码1QT+=coreguinetwork23greaterThan(QT_MAJOR_VERSION,4):QT+=widgets45CONFIG+=c++1167anyQtfeaturethathasbeenmarkeddeprecated(theexac+=QT_DEPRECATED_WARNINGS1213Inordertodoso,+=QT_DISABLE_DEPRECATED_BEFORE=0:=/tmp/${TARGET}/bin27else:unix:!android:=/opt/${TARGET}/bin28!isEmpty():INSTALLS+=target在头文件“”具体代码如下。
编程后的代码/******************************************************************Copyright©DengZhimaoCo.,*@projectName08_tcpserver*@*@authorDengZhimao*@email1252699831@*@*@date2021-04-13*******************************************************************/1defineMAINWINDOW_H34includeQTcpServer6includeQVBoxLayout8includeQPushButton10includeQLabel12includeQSpinBox14includeQLineEdit16includeQDebug1819classMainWindow:publicQMainWindow20{21Q_OBJECT2223public:24MainWindow(QWidget*parent=nullptr);25~MainWindow();2627private:28/*tcp服务器*/29QTcpServer*tcpServer;3031/*通信套接字*/32QTcpSocket*tcpSocket;3334/*按钮*/35QPushButton*pushButton[4];3637/*标签文本*/38QLabel*label[2];3940/*水平容器*/41QWidget*hWidget[3];4243/*水平布局*/44QHBoxLayout*hBoxLayout[3];4546/*垂直容器*/47QWidget*vWidget;4849/*垂直布局*/50QVBoxLayout*vBoxLayout;5152/*文本浏览框*/53QTextBrowser*textBrowser;5455/*用于显示本地ip*/56QComboBox*comboBox;5758/*用于选择端口*/59QSpinBox*spinBox;6061/*文本输入框*/62QLineEdit*lineEdit;6364/*存储本地的ip列表地址*/65QListQHostAddressIPlist;6667/*获取本地的所有ip*/68voidgetLocalHostIP();6970privateslots:71/*客户端连接处理槽函数*/72voidclientConnected();7374/*开始监听槽函数*/75voidstartListen();7677/*停止监听槽函数*/78voidstopListen();7980/*清除文本框时的内容*/81voidclearTextBrowser();8283/*接收到消息*/84voidreceiveMessages();8586/*发送消息*/87voidsMessages();8889/*连接状态改变槽函数*/90voidsocketStateChange(QAbstractSocket::SocketState);91};92include""23MainWindow::MainWindow(QWidget*parent)4:QMainWindow(parent)5{6/*设置主窗体的位置与大小*/7this-setGeometry(0,0,800,480);89/*实例化tcp服务器与tcp套接字*/10tcpServer=newQTcpServer(this);11tcpSocket=newQTcpSocket(this);1213/*开始监听按钮*/14pushButton[0]=newQPushButton();15/*停止监听按钮*/16pushButton[1]=newQPushButton();17/*清空聊天文本按钮*/18pushButton[2]=newQPushButton();19/*发送消息按钮*/20pushButton[3]=newQPushButton();2122/*水平布局一*/23hBoxLayout[0]=newQHBoxLayout();24/*水平布局二*/25hBoxLayout[1]=newQHBoxLayout();26/*水平布局三*/27hBoxLayout[2]=newQHBoxLayout();28/*水平布局四*/29hBoxLayout[3]=newQHBoxLayout();3031/*水平容器一*/32hWidget[0]=newQWidget();33/*水平容器二*/34hWidget[1]=newQWidget();35/*水平容器三*/36hWidget[2]=newQWidget();3738vWidget=newQWidget();39vBoxLayout=newQVBoxLayout();4041/*标签实例化*/42label[0]=newQLabel();43label[1]=newQLabel();4445lineEdit=newQLineEdit();46comboBox=newQComboBox();47spinBox=newQSpinBox();48textBrowser=newQTextBrowser();4950label[0]-setText("监听IP地址:");51label[1]-setText("监听端口:");5253/*设置标签根据文本文字大小自适应大小*/54label[0]-setSizePolicy(QSizePolicy::Fixed,55QSizePolicy::Fixed);56label[1]-setSizePolicy(QSizePolicy::Fixed,57QSizePolicy::Fixed);5859/*设置端口号的范围,注意不要与主机的已使用的端口号冲突*/60spinBox-setRange(10000,99999);6162pushButton[0]-setText("开始监听");63pushButton[1]-setText("停止监听");64pushButton[2]-setText("清空文本");65pushButton[3]-setText("发送消息");6667/*设置停止监听状态不可用*/68pushButton[1]-setEnabled(false);6970/*设置输入框默认的文本*/71lineEdit-setText("正点原子论坛");7273/*水平布局一添加内容*/74hBoxLayout[0]-addWidget(pushButton[0]);75hBoxLayout[0]-addWidget(pushButton[1]);76hBoxLayout[0]-addWidget(pushButton[2]);7778/*设置水平容器一的布局为水平布局一*/79hWidget[0]-setLayout(hBoxLayout[0]);8081/*水平布局二添加内容*/82hBoxLayout[1]-addWidget(label[0]);83hBoxLayout[1]-addWidget(comboBox);84hBoxLayout[1]-addWidget(label[1]);85hBoxLayout[1]-addWidget(spinBox);8687/*设置水平容器二的布局为水平布局二*/88hWidget[1]-setLayout(hBoxLayout[1]);8990/*水平布局三添加内容*/91hBoxLayout[2]-addWidget(lineEdit);92hBoxLayout[2]-addWidget(pushButton[3]);9394/*设置水平容器三的布局为水平布局一*/95hWidget[2]-setLayout(hBoxLayout[2]);9697/*垂直布局添加内容*/98vBoxLayout-addWidget(textBrowser);99vBoxLayout-addWidget(hWidget[1]);100vBoxLayout-addWidget(hWidget[0]);101vBoxLayout-addWidget(hWidget[2]);102103/*设置垂直容器的布局为垂直布局*/104vWidget-setLayout(vBoxLayout);105106/*居中显示*/107setCentralWidget(vWidget);108109/*获取本地ip*/110getLocalHostIP();111112/*信号槽连接*/113connect(pushButton[0],SIGNAL(clicked()),114this,SLOT(startListen()));115connect(pushButton[1],SIGNAL(clicked()),116this,SLOT(stopListen()));117connect(pushButton[2],SIGNAL(clicked()),118this,SLOT(clearTextBrowser()));119connect(pushButton[3],SIGNAL(clicked()),120this,SLOT(sMessages()));121connect(tcpServer,SIGNAL(newConnection()),122this,SLOT(clientConnected()));123}124125MainWindow::~MainWindow()126{127}128129/*新的客户端连接*/130voidMainWindow::clientConnected()131{132/*获取客户端的套接字*/133tcpSocket=tcpServer-nextPingConnection();134/*客户端的ip信息*/135QStringip=tcpSocket-peerAddress().toString();136/*客户端的端口信息*/137qint16port=tcpSocket-peerPort();138/*在文本浏览框里显示出客户端的连接信息*/139textBrowser-app("客户端已连接");140textBrowser-app("客户端ip地址:"141+ip);142textBrowser-app("客户端端口:"143+QString::number(port));144145connect(tcpSocket,SIGNAL(readyRead()),146this,SLOT(receiveMessages()));147connect(tcpSocket,148SIGNAL(stateChanged(QAbstractSocket::SocketState)),149this,150SLOT(socketStateChange(QAbstractSocket::SocketState)));151}152153/*获取本地IP*/154voidMainWindow::getLocalHostIP()155{156///*获取主机的名称*/157//QStringhostName=QHostInfo::localHostName();158159///*主机的信息*/160//QHostInfohostInfo=QHostInfo::fromName(hostName);161162///*ip列表,addresses返回ip地址列表,注意主机应能从路由器获取到163//*IP,否则可能返回空的列表(ubuntu用此方法只能获取到环回IP)*/164//IPlist=();165//qDebug()IPlistl;166167///*遍历IPlist*/168//foreach(QHostAddressip,IPlist){169//if(()==QAbstractSocket::IPv4Protocol)170//comboBox-addItem(());171//}172173/*获取所有的网络接口,174*QNetworkInterface类提供主机的IP地址和网络接口的列表*/175QListQNetworkInterfacelist176=QNetworkInterface::allInterfaces();177178/*遍历list*/179foreach(QNetworkInterfaceinterface,list){180181/*QNetworkAddressEntry类存储IP地址子网掩码和广播地址*/182QListQNetworkAddressEntryentryList183=();184185/*遍历entryList*/186foreach(QNetworkAddressEntryentry,entryList){187/*过滤IPv6地址,只留下IPv4*/188if(().protocol()==189QAbstractSocket::IPv4Protocol){190comboBox-addItem(().toString());191/*添加到IP列表中*/192();193}194}195}196}197198/*开始监听*/199voidMainWindow::startListen()200{201/*需要判断当前主机是否有IP项*/202if(comboBox-currentIndex()!=-1){203qDebug()"startlisten"l;204tcpServer-listen(IPlist[comboBox-currentIndex()],205spinBox-value());206207/*设置按钮与下拉列表框的状态*/208pushButton[0]-setEnabled(false);209pushButton[1]-setEnabled(true);210comboBox-setEnabled(false);211spinBox-setEnabled(false);212213/*在文本浏览框里显示出服务端*/214textBrowser-app("服务器IP地址:"215+comboBox-currentText());216textBrowser-app("正在监听端口:"217+spinBox-text());218}219}220221/*停止监听*/222voidMainWindow::stopListen()223{224qDebug()"stoplisten"l;225/*停止监听*/226tcpServer-close();227228/*如果是连接上了也应该断开,如果不断开客户端还能继续发送信息,229*因为socket未断开,还在监听上一次端口*/230if(tcpSocket-state()==tcpSocket-ConnectedState)231tcpSocket-disconnectFromHost();232233/*设置按钮与下拉列表框的状态*/234pushButton[1]-setEnabled(false);235pushButton[0]-setEnabled(true);236comboBox-setEnabled(true);237spinBox-setEnabled(true);238239/*将停止监听的信息添加到文本浏览框中*/240textBrowser-app("已停止监听端口:"241+spinBox-text());242}243244/*清除文本浏览框里的内容*/245voidMainWindow::clearTextBrowser()246{247/*清除文本浏览器的内容*/248textBrowser-clear();249}250251/*服务端接收消息*/252voidMainWindow::receiveMessages()253{254/*读取接收到的消息*/255QStringmessages="客户端:"+tcpSocket-readAll();256textBrowser-app(messages);257}258259/*服务端发送消息*/260voidMainWindow::sMessages()261{262if(NULL==tcpSocket)263return;264265/*如果已经连接*/266if(tcpSocket-state()==tcpSocket-ConnectedState){267/*发送消息*/268tcpSocket-write(lineEdit-text().toUtf8().data());269270/*在服务端插入发送的消息*/271textBrowser-app("服务端:"+lineEdit-text());272}273}274275/*服务端状态改变*/276voidMainWindow::socketStateChange(QAbstractSocket::SocketStatestate)277{278switch(state){279caseQAbstractSocket::UnconnectedState:280textBrowser-app("scoket状态:UnconnectedState");281break;282caseQAbstractSocket::ConnectedState:283textBrowser-app("scoket状态:ConnectedState");284break;285caseQAbstractSocket::ConnectingState:286textBrowser-app("scoket状态:ConnectingState");287break;288caseQAbstractSocket::HostLookupState:289textBrowser-app("scoket状态:HostLookupState");290break;291caseQAbstractSocket::ClosingState:292textBrowser-app("scoket状态:ClosingState");293break;294caseQAbstractSocket::ListeningState:295textBrowser-app("scoket状态:ListeningState");296break;297caseQAbstractSocket::BoundState:298textBrowser-app("scoket状态:BoundState");299break;300default:301break;302}303}未完待续.
很赞哦!(122)