QT程序 与 Linux应用程序 进程间数据通信实例(TCP/IP方案)

27 篇文章 5 订阅

简述

Qt 提供了四种进程间通信的方式:

  1. 使用共享内存(shared memory)交互:这是 Qt 提供的一种各个平台均有支持的进程间交互的方式。
  2. TCP/IP:其基本思想就是将同一机器上面的两个进程一个当做服务器,一个当做客户端,二者通过网络协议进行交互。除了两个进程是在同一台机器上,这种交互方式与普通的 C/S 程序没有本质区别。Qt 提供了 QNetworkAccessManager 对此进行支持。
  3. D-Bus:freedesktop 组织开发的一种低开销、低延迟的 IPC 实现。Qt 提供了 QtDBus 模块,把信号槽机制扩展到进程级别(因此我们前面强调是“普通的”信号槽机制无法实现 IPC),使得开发者可以在一个进程中发出信号,由其它进程的槽函数响应信号。
  4. QCOP(Qt COmmunication Protocol):QCOP 是 Qt 内部的一种通信协议,用于不同的客户端之间在同一地址空间内部或者不同的进程之间的通信。目前,这种机制只用于 Qt for Embedded Linux 版本。

Qt之进程间通信(TCP/IP)

首先准备好QT程序,思路是在QT端准备TCP的服务端,然后用其他进程或者其他程序给TCP服务端发送数据,验证接收

主程序中程序如下,主要实现了TCP的接收,滑动条显示

#include "widget.h"
#include "ui_widget.h"

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

    tcpServer = new QTcpServer(this);
    tcpSocket = new QTcpSocket(this);

    // 设置slider控件范围
    ui->slider->setRange(0, 100);
    // 设置spinBox控件的最小值
    ui->slider->setRange(0, 100);
    // 设置spinBox步长为1
    ui->slider->setSingleStep(1);
    // 设置spinBox后缀
    // ui->spinBox->setSuffix("");
    // 设置输出显示前缀
    // ui->spinbox->setPrefix("");
    // 信号和槽 当滑动条的值发生改变时,即产生一个valueChanged(int)信号 设置QLineEdit控件的显示文本
    connect(ui->slider, SIGNAL(valueChanged(int)), this, SLOT(setLineEditValue(int)));
    // 信号和槽 当数值发生改变时,即产生一个lineChanged(int)信号 设置slider控件的显示滑动条
    connect(ui->spinBox, SIGNAL(valueChanged(int)), this, SLOT(setSliderEditValue(int)));
    // 设置滑动条控件的值
    // ui->slider->setValue(0);
}

void Widget::setLineEditValue(int value)
{
    int pos = ui->slider->value();
//    QString str = QString("%1").arg(pos);
    ui->spinBox->setValue(pos);

    if(pos != last_pos) {
        last_pos = pos;
    }
}

void Widget::setSliderEditValue(int value)
{
    int pos;

    pos = ui->spinBox->value();
    ui->slider->setValue(pos);

    if(pos != last_pos) {
        last_pos = pos;
    }
}

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

void Widget::on_openBt_clicked()
{      
    /* newConnection():This signal is emitted every time a new connection is available. */
    connect(tcpServer, SIGNAL(newConnection()), this, SLOT(newConnection_Slot()));
    /*
     * QHostAddress::Any 监听来自所有人的连接
     * listen返回值是无符号类型,所以要对text进行转换
     * 监听所有的设备,读取端口号
     */
    if( (tcpServer->listen(QHostAddress::Any, ui->portEdit->text().toUInt())) == true ) {
        QMessageBox::information(this, "提示", "TCP端口号开始监听!");
    } else {
        QMessageBox::warning(this, "警告", "TCP端口号监听失败!");
    }

}
void Widget::newConnection_Slot()
{
    /* 获得已经连接的客户端的socket */
    tcpSocket = tcpServer->nextPendingConnection();
    /* 获得了socket之后就可以进行读写的操作 */
    connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(readyRead_Slot()));
}

void Widget::readyRead_Slot()
{
    QString buf;
    bool ok;

    buf = tcpSocket->readAll();
    ui->recvEdit->appendPlainText(buf);         // ui界面的接收框显示
    if(buf == "-1") {
        count = -1;
    }else if(buf == "1") {
        count = 1;
    }
    ui->spinBox->setValue(last_pos + count);
    count = 0;
}


void Widget::on_closeBt_clicked()
{
    tcpServer->close();
}

void Widget::on_sendBt_clicked()
{
    tcpSocket->write(ui->sendEdit->text().toLocal8Bit().data());
}

void Widget::on_pushButton_clicked()
{
    ui->recvEdit->clear();
}

在这里插入图片描述

测试QT

QT服务端搭建好了,怎么才能简单的测试呢?

因为我是windows平台,所以直接使用终端进行发送

echo “1| nc 127.0.0.1 5000

注意:如果找不到nc命令,那就去下载: https://eternallybored.org/misc/netcat/

解压后,把nc.exe或者nc64.exe复制到C:\Windows\System32目录
在这里插入图片描述
运行cmd,查看命令:nc -h
在这里插入图片描述
如果我们在QT界面中可以看到接收的程序,那么就成功了

Linux程序

最后的目的还是Linux 的应用程序和QT数据的传输

通过程序设计,读取旋转编码器的值,并且提取出来我们需要的+1和-1的两个状态值

以及打开TCP服务

 /*                       ,%%%%%%%%,
 *                      ,%%/\%%%%/\%%
 *                     ,%%%\c''''J/%%%
 *           %.        %%%%/ o  o \%%%
 *           `%%.      %%%%       |%%%
 *            `%%      `%%%%(__Y__)%%'
 *            //        ;%%%%`\-/%%%'
 *            ((      /   `%%%%%%%'
 *             \\     .'           |
 *              \\   /        \  | |
 *               \\/          ) | |
 *                \          /_ | |__
 *                (____________))))))) 攻城狮 2019信号 ShengZM
 *
 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/input.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>


#define NOKEY               0
#define SERVPORT            5000                        // 端口号
#define MAXDATASIZE         100

int main(int argc, char *argv[])
{
	int rotary_encoder_fd;	
    char ret[2]; 
	struct input_event rotary_event;
	char *dev;

    int sockfd, sendbytes;
    char buf[MAXDATASIZE];
    struct hostent *host;
    struct sockaddr_in serv_addr;
    char *hostname = "192.168.0.2";		

    /*地址解析函数*/
    // gethostbyname函数(为了获得对方的IP地址)
    if((host = gethostbyname(hostname)) == NULL){
        perror("gethostbyname");
        exit(1);
    }

    /*创建socket*/
    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
        perror("socket");
        exit(1);
    }

    /*设置sockaddr_in结构体中相关参数*/
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port   = htons(SERVPORT);                             // 设置通信的端口号
    serv_addr.sin_addr   = *((struct in_addr *)host -> h_addr);
    bzero(&(serv_addr.sin_zero), 8);

    /*调用connect函数主动发起对服务器端的连接*/
    if(connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) == -1){
        perror("connect");
        exit(1);
    }

    setvbuf(stdout, (char *)NULL, _IONBF, 0);                                  //disable stdio out buffer;
    // dev = getenv("KEYPAD_DEV");
      
    rotary_encoder_fd = open("/dev/input/event2", O_RDONLY);                  // 旋转编码器
	if(rotary_encoder_fd <= 0)
	{
        printf("open %s device error!\n",dev);
		return 0;
	}

	while(1) {	
        if(read(rotary_encoder_fd, &rotary_event, sizeof(rotary_event)) == sizeof(rotary_event)) {
		    if(rotary_event.type == 2) {
		        if(rotary_event.code == 0 ) {
		        	//printf("%d \n", t.code);
		        	switch(rotary_event.value) {
		        		case 1:
		            		printf("rotary encoder: 1 right \n");
                            /*发消息给服务器端*/
                            if((sendbytes = send(sockfd, "1", 1, 0)) == -1){
                                perror("send");
                                exit(1);
                            }
		            	break;

		            	case -1:
		            		printf("rotary encoder:-1 left \n");
                            if((sendbytes = send(sockfd, "-1", 2, 0)) == -1){
                                perror("send");
                                exit(1);
                            }
		            	break;

		            	default:
		            	break;
		            }
                    
		        }
            }
		}
	}	
    close(sockfd);
	close(rotary_encoder_fd);
	
    return 0;
}

因为程序中的IP是windows电脑的IP,我们直接运行嵌入式中的应用程序,通过旋转编码器就可以来修改windows环境下的QT
在这里插入图片描述

QT交叉编译到嵌入式

最后就是把QT通过交叉编译到嵌入式中

qmake
make

在这里插入图片描述

scp *** root@192.168.0.232:/work

嵌入式中

export DISPALU=:0.0

在这里插入图片描述

 ./Qt_Tcp_Server &

在这里插入图片描述



在这里插入图片描述
在这里插入图片描述

  • 2
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
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协议进行网络通信。这样,我们就可以实现控制和监测数字仪器仪表的操作。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值