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

文章目录

  • 简述
  • Qt之进程间通信(TCP/IP)
  • 测试QT
  • Linux程序
  • QT交叉编译到嵌入式

简述

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程序 与 Linux应用程序 进程间数据通信实例(TCP/IP方案)_第1张图片

测试QT

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

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

echo “1| nc 127.0.0.1 5000

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

解压后,把nc.exe或者nc64.exe复制到C:\Windows\System32目录
QT程序 与 Linux应用程序 进程间数据通信实例(TCP/IP方案)_第2张图片
运行cmd,查看命令:nc -h
QT程序 与 Linux应用程序 进程间数据通信实例(TCP/IP方案)_第3张图片
如果我们在QT界面中可以看到接收的程序,那么就成功了

Linux程序

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

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

以及打开TCP服务

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

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 


#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程序 与 Linux应用程序 进程间数据通信实例(TCP/IP方案)_第4张图片

QT交叉编译到嵌入式

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

qmake
make

QT程序 与 Linux应用程序 进程间数据通信实例(TCP/IP方案)_第5张图片

scp *** root@192.168.0.232:/work

嵌入式中

export DISPALU=:0.0

在这里插入图片描述

 ./Qt_Tcp_Server &

在这里插入图片描述



QT程序 与 Linux应用程序 进程间数据通信实例(TCP/IP方案)_第6张图片
QT程序 与 Linux应用程序 进程间数据通信实例(TCP/IP方案)_第7张图片

你可能感兴趣的:(Linux,i.MX6,网络协议,linux,socket,嵌入式)