QT中进行TCP/IP网络通信服务器的基础配置与简单理解

最近在学QT,虽然只是想入门,达到最简单的使用效果,以下是我一天的学习QT中TCP网络通讯如何进行基础配置与TCP网络通讯的简单理解。看配置的话建议直接跳转到“快速入门及配置”。

(2024.06.03添加)最近看了一篇非常详细讲TCP/IP服务(非常详细地讲了原理,三次握手、四次挥手等),这里建议看一下:https://www.cnblogs.com/crazymakercircle/p/14499211.html

目录:

1 TCP/IP协议族简单介绍与理解

1.1 摘抄自他人对TCP/IP协议族的理解与讲解

1.2 个人对TCP/IP协议族的浅显理解

2 在QT中配置TCP服务

2.1 整体思路

2.2 快速入门及配置

2.3 创建、应用TCP服务器服务

2.4 创建、应用TCP客户端端服务

3 可能遇到的问题


正文:

1 TCP/IP协议族简单介绍与理解

1.1 摘抄自他人对TCP/IP协议族的理解与讲解

我看了两篇文章

第一篇文章:https://zhuanlan.zhihu.com/p/33889997
第二篇文章https://blog.csdn.net/Jacky_Feng/article/details/114977261

看了两位作者对TCP/IP协议族的理解,以下是他们对TCP的介绍,我就直接复制粘贴过来了,感兴趣的建议直接去看原文章。
TCP通讯的定义:TCP (Transmission Control Protocol)和UDP(User Datagram Protocol)协议属于传输层协议。其中TCP提供IP环境下的数据可靠传输,它提供的服务包括数据流传送、可靠性、有效流控、全双工操作和多路复 用。通过面向连接、端到端和可靠的数据包发送。
作用:TCP/IP 是用于因特网 (Internet) 的通信协议。 TCP/IP 通信协议是对计算机必须遵守的规则的描述,只有遵守这些规则,计算机之间才能进行通信。
优点: 1.TCP(Transimision Control Protocal)
2.传输控制协议
3.可靠的、面向连接的协议
4.传输效率低
5.UDP(User Datagram Protocal)
6.用户数据报协议
7.不可靠的、无连接的服务
8.传输效率高

1.2 个人对TCP/IP协议族的浅显理解

我基于对两位作者文章的理解,提出我对对TCP/IP协议族通讯过程的浅显理解:TCP指的不是单个具体的协议,而是一个庞大的协议族,是很多通讯协议的大集合。
通讯协议需要遵守ISO(国际标准化组织)制定的七大体系结构,但我们所用的TCP属于传输层的东西,传统上来说TCP/IP被认为是一个四层协议。协议的分层可见下图。以下我举了一个我自己理解的简单供读者参考。
图1
就像我们要给别人发一条信息,我们可以选择写信、发邮件、用手机发信息(对应通讯协议),那我们选择使用手机发信息,然而用手机发信息又可以选择的应用有很多,短信、电话、QQ、微信等等(对应应用层),最终我们选择了微信,我们给A朋友发了一则消息“Hello World”,这条消息会先通过相关协议(TCP协议)封装成机代码格式(很不专业的叫法,理解下),通过网络协议(IP)进行再封装,封装成符合网络传输的代码格式,最终由手机的网卡(数据链路层)通过WIFI、运营商网络等(物理层)发送给A朋友。A朋友则会经历一番逆操作,便可以在手机上看到我们发送的“Hello World”。(这一流程,我表述的可能很不准确甚至有误,欢迎大家私信我)我将这一过程整理成流程图,可见以下流程图。图2
跟据以上例子,应该可以简单理解这一通讯过程了,本文主要去简单配置、使用TCP/IP协议,所以我们只用关系这两个地方即可,其他数据链路层、物理层其实都属于硬件部分,这部分我们不做讨论。

2 在QT中配置TCP服务

2.1 整体思路以及QT中用到的一些函数

在TCP通讯中,TCP通讯逻辑往往遵守以下流程图。也就是说,我们完全可以跟着这张图进行编程。图上更是标明了什么时候用什么函数,绑定QT的什么信号。在这里插入图片描述

端口号的取值范围一般是0~65535,在计算机中,1024以下的一般都是系统服务的各种端口,这部分端口一般情况下不要去使用。在同一计算机中,端口使用不要重复,也就是每一个连接要对应一个端口号。本文使用的端口号是9090。

2.2 快速入门及配置

在QT中,它自带了TCP服务,无需我们再多下载其他东西。提到TCP服务,俩设备通讯肯定是绕不开的基础,那么我们可以创建一个简单的对话框,来辅助我们进行调试。
我们先做一个服务器端的网络通讯。为了方便我们观察是否通讯成功,我们可以使用QT拉一个简单的页面,页面如下图:在这里插入图片描述

为了方便对代码的理解,我这里将我给这些组件的命名标注(红字)如下图:
在这里插入图片描述

2.3 创建、应用TCP服务器服务

本文直接在本地模拟了TCP服务器通讯,所以不用设置通讯地址,只用配置端口即可。
本文要实现的目标是能将项目配置成TCP服务器,然后通过网络调试软件充当客户端,两者进行通讯,服务器与客户端通讯的消息会被记录在历史信息中,服务器向客户端发送的消息可以通过“发送消息”文本框进行输入,并通过“发送消息”按钮进行发送。
所以综上,我们只需要配置TCP服务器的端口号便可达到TCP服务器的基础功能。
我这里使用的是QT的qmake系统模板(Build system),5.14.2 32-bit的版本。在QT中,我们要使用TCP服务,以下步骤是用来制作TCP服务器的:
本文整个步骤都是按照“整体思路以及QT中用到的一些函数”中的流程图(以下简称为流程图)来写的。
1.将网络模块添加进项目,在项目中的.pro文件中第一行,添加上network代码(这一步是死的步骤),如下图:在这里插入图片描述
这一步是将QT的网络模块添入项目中,这个网络模块是QT自带的东西,QT只是在创建项目时没有引入这个模块而已,也可以简单理解为给整个项目引入网络服务包的一个操作。
2.在mainwindow.h文件中引入QTcp服务,并声明QTcpServer、QTcpSocket两个对象,QTcpServer用以配置QTcpSocket对象,这一步也就对应着流程图中的socket()这一步,过程如下图:在这里插入图片描述

这里声明的这两个对象,目的是在整个项目进行使用,根据自己的情况,也可以将它们声明在自己需要的地方(但我感觉一般都会是全局更方便吧)。
3.实例化m_s,并在m_s中设置端口与IP地址。
在这里插入图片描述
这里第一步、第三步、第四步是必要的,第二步属于一个槽函数的设置,第五步属于一个UI的设置。第一、三步对应流程图的bind()步骤设计,因为我们要监听所有IP地址,所以我们不用对IP地址进行设计,只需要设置端口就好,也就是只获取了端口号,让其转换成了符合listen()函数的16位无符号数字。第四步也就是设置了lister()步骤。
4.到此我们完成了accept()之前的所有设置,接下来就是调用将信号QTcpServer::newConnection与包含nextPendingConnection()的槽函数绑定在一起,翻译过来就是当有新设备连接时,就调用nextPendingConnection()函数,获取客户端的QTcpSocket。步骤如下:
在这里插入图片描述
这里的第一步是完成了accept(),然后第二步是完成了socket()。第三步属于一个UI优化。
5.接下来就是绑定read()与write()了,read()对应一个QTcpSocket::newConnetcion信号和readAll()函数,writer()对应了一个发送按钮的槽函数,也就是说当按钮被按下时,就会触发write()函数,进行发送信息,步骤如下:在这里插入图片描述
到此其实已经能与客户端进行正常通讯了,也就是说服务器端的基础功能其实快配置完了,现在就差最后一步close了。
6.配置close()其实最简单了,就是当客户端与服务器断开连接时会产生一个QTcpSocket::disconnected信号,我们只需要在该信号被触发时,去关闭m_t即可。步骤如下:
在这里插入图片描述
到此,QT中TCP服务器端已经配置完毕,我们可以通过网络调试助手(我在这个网址下载的网络调试助手:https://soft.3dmgame.com/down/213757.html)进行调试,试试看是否成功。效果如下:
在这里插入图片描述
附上服务器端源码:
.pro文件中就添加了一句,这里就不展示了。
mainwindow.cpp文件源码:
代码中有很多被注释掉的代码,那些代码与配置TCP服务器端无关,它们只是一些优化UI的代码,然后我这些代码引入了我自己的一个素材包,所以你取消这些被注释的代码可能会导致你的代码报错。

#include "mainwindow.h"  
#include "ui_mainwindow.h"  
#include "QLabel"  
  
MainWindow::MainWindow(QWidget *parent)  
    : QMainWindow(parent)  
    , ui(new Ui::MainWindow)  
{  
    ui->setupUi(this);  
  
    //用以设置图标  
//    m_status = new QLabel;  
    //设置图标  
//    ui->statusbar->addWidget(new QLabel("连接状态为:"));//在状态栏中添加一个QLabel标签组件  
//    m_status->setPixmap(QPixmap(":/new/prefix1/cuowu.png").scaled(15,15));//设置连接失败图片  
//    ui->statusbar->addWidget(m_status);  
  
    m_s = new QTcpServer(this); //实例化m_s对象  
    ui->COM_lineEdit->setText("9090");  
  
    connect(m_s,&QTcpServer::newConnection,this,[=](){  
        //检查是否连接成功  
        m_t = m_s->nextPendingConnection();  
  
//        m_status->setPixmap(QPixmap(":/new/prefix1/duigou.png").scaled(15,15));//设置连接失败图片  
//        ui->statusbar->addWidget(m_status);//设置连接成功图片  
  
        ui->COM_record->append("-----客户端完成与服务器的连接-----");  
        //接收数据  
        connect(m_t,&QTcpSocket::readyRead,this,[=](){  
            QByteArray buf = m_t->readAll();  
            ui->COM_record->append("客户端:" + buf);   //将数据展示出来  
        });  
  
        connect(m_t,&QTcpSocket::disconnected,this,[=](){   //关闭监听  
  
//            m_status->setPixmap(QPixmap(":/new/prefix1/cuowu.png").scaled(15,15));//设置连接失败图片  
//            ui->statusbar->addWidget(m_status);  
  
            ui->COM_record->append("-----与服务器断开连接-----");  
            m_t->close();  
            m_t->deleteLater();  
        });  
    });  
  
}  
  
MainWindow::~MainWindow()  
{  
    delete ui;  
}  
  
  
void MainWindow::on_COM_pushButton_clicked()  
{  
    unsigned short port = ui->COM_lineEdit->text().toUShort();  //转成16位的无符号数  
    m_s->listen(QHostAddress::Any,port);    //打开TCP服务器端的监听  
    ui->COM_pushButton->setDisabled(true);  //将监听按钮设置为禁用  
}  
  
void MainWindow::on_sendMessage_pushButton_clicked()  
{  
    QString message = ui->sendMessage_record->toPlainText();//获取将要发送的文本  
    QByteArray sendMessage = message.toUtf8();//将文本数据转换为UTF-8  
    m_t->write(sendMessage);//发送数据  
    ui->COM_record->append("服务器:" + sendMessage);//将发送数据记录下来  
    ui->sendMessage_record->clear();//将发送数据框清空  
}  

2.4 创建、应用TCP客户端端服务

创建客户端的UI界面如下图所示:在这里插入图片描述

这里其实与上面的服务器端大同小异,只要能看懂服务器端,那看懂客户端那就是很简单的,这里我直接附上源码吧。
mainwindow.cpp文件:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "QLabel"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    //用以设置图标
//    m_status = new QLabel;
    //设置图标
//    ui->statusbar->addWidget(new QLabel("连接状态为:"));//在状态栏中添加一个QLabel标签组件
//    m_status->setPixmap(QPixmap(":/new/prefix1/cuowu.png").scaled(15,15));//设置连接失败图片
//    ui->statusbar->addWidget(m_status);

    m_socket = new QTcpSocket(this);
    ui->COM_lineEdit->setText("9090");

    //与服务器连接成功
    connect(m_socket,&QTcpSocket::connected,this,[=](){ //当成功连接时会触发这个信号
//        m_status->setPixmap(QPixmap(":/new/prefix1/duigou.png").scaled(15,15));//设置连接失败图片
//        ui->statusbar->addWidget(m_status);//设置连接成功图片

        ui->COM_record->append("-----客户端完成与服务器的连接-----");
    });

    //接收数据
    connect(m_socket,&QTcpSocket::readyRead,this,[=](){ //当有新数据时,会触发这个信号
        QByteArray buf = m_socket->readAll();
        ui->COM_record->append("服务器:" + buf);   //将数据展示出来
    });

    //断开连接
    connect(m_socket,&QTcpSocket::disconnected,this,[=](){   //当与服务器断开时出发这个信号
        ui->COM_record->append("-----与服务器断开连接-----");
        ui->IP_pushButton->setEnabled(false);
        ui->COM_pushButton->setEnabled(true);


        //设置状态栏图标
//        m_status->setPixmap(QPixmap(":/new/prefix1/cuowu.png").scaled(15,15));//设置连接失败图片
//        ui->statusbar->addWidget(m_status);
    });
}

MainWindow::~MainWindow()
{
    delete ui;
}


void MainWindow::on_COM_pushButton_clicked()
{
    QString ip = ui->IP_lineEdit->text();
    unsigned short port = ui->COM_lineEdit->text().toUShort();  //转成16位的无符号数
    //连接服务器
    m_socket->connectToHost(QHostAddress(ip),port);

    ui->COM_pushButton->setDisabled(true);  //将监听按钮设置为禁用
    ui->IP_pushButton->setDisabled(false);
}

void MainWindow::on_sendMessage_pushButton_clicked()
{
    QString message = ui->sendMessage_record->toPlainText();//获取将要发送的文本
    QByteArray sendMessage = message.toUtf8();//将文本数据转换为UTF-8
    m_socket->write(sendMessage);//发送数据
    ui->COM_record->append("服务器:" + sendMessage);//将发送数据记录下来
    ui->sendMessage_record->clear();//将发送数据框清空
}

void MainWindow::on_IP_pushButton_clicked()
{
    m_socket->close();
    ui->COM_pushButton->setEnabled(true);
    ui->IP_pushButton->setEnabled(false);
}

到此QT中对TCP客户端、服务器端的配置已经完成,并能实现基础功能。

3 可能遇到的问题

1.我的客户端和服务器端处于同一个IP、端口中为什么连接不上?
检查一下端口号是否大于1024,我建议直接用9000以上的;IP可以尝试使用127.0.0.1,也就是本地IP,有的时候使用198.XXX这个IP可能会被电脑的防火墙阻止连接。

4 更新日志

这里其实不重要,但我有点强迫症,想要记录一下修改的地方。
2024-04-30:修改了2.1中的流程图,完善了TCP客户端的部分(原本只有服务器端的详细介绍)。

  • 16
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Qt是一个跨平台的C++应用程序开发框架,可以用来开发图形用户界面(GUI)应用程序。Visa库是一种用于与仪器通信的底层库,为开发者提供了与仪器进行通信的接口。TCP/IP是一种广泛应用于网络通信协议。 在Qt,我们可以使用Visa库与数字仪器仪表进行TCP/IP通信。首先,我们需要在项目包含Visa库的头文件,并链接Visa库。然后,我们可以使用Visa的相关函数来建立与数字仪器仪表的连接。 首先,我们需要创建一个Visa实例。我们可以通过Visa的函数来获取可用的Visa资源,如Visa设备列表。然后,我们可以根据Visa资源的地址来打开与数字仪器仪表的连接。 一旦成功建立连接,我们可以使用Visa库提供的函数来发送和接收数据。我们可以使用Visa的写入函数来发送指令或查询到数字仪器仪表。并使用Visa的读取函数来接收仪器的响应或数据。通过这种方式,我们可以实现与数字仪器仪表的通信。 使用Qt的网络模块,我们可以使用TCP/IP协议来与数字仪器仪表进行网络通信。我们可以创建一个QTcpSocket实例,然后使用其函数来建立与数字仪器仪表的连接。通过设置主机地址和端口号,我们可以实现与数字仪器仪表的连接。 一旦成功建立连接,我们可以使用QTcpSocket的函数来发送和接收数据。我们可以使用write函数来发送指令或查询到数字仪器仪表。并使用read函数来接收仪器的响应或数据。 综上所述,Qt可以使用Visa库与数字仪器仪表进行TCP/IP通信。通过Visa库,我们可以使用Visa的API函数来建立和管理与数字仪器仪表的连接,通过QTcpSocket,我们可以使用TCP/IP协议进行网络通信。这样,我们就可以实现控制和监测数字仪器仪表的操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值