QT程序与 Linux应用程序运 进程间数据通信实例

Posted “逛丢一只鞋”

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了QT程序与 Linux应用程序运 进程间数据通信实例相关的知识,希望对你有一定的参考价值。

简述

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 &




以上是关于QT程序与 Linux应用程序运 进程间数据通信实例的主要内容,如果未能解决你的问题,请参考以下文章

Qt学习之路(58): 进程间交互(QProcess.readAllStandardOutput可以读取控制台的输出)

Qt使用QProcess进程间双向通信(linux和win系统)

PHP与Linux进程间的通信

Qt进程间通信之QSharedMemory示例

Qt进程间通信之QSharedMemory示例

深入Linux内核架构——锁与进程间通信