把最近工作总结下。
之前在嵌入 python 解释器的过程中,我们没有处理这样一种情况:当 Python 解释器正在执行一个阻塞操作 ( 比如 socket server 在监听一个客户端连入 ) ,这时我们需要终止解释器的运行,该如何操作呢?
在Qt线程中不容易实现该功能,如果在 socket 监听时终止 python 解释器,那么再次运行时端口就会显示被占用,因为资源没有清理。为了解决这种情况,我们让解释器运行在一个进程中。这样在需要停止时,我们可以发送 kill 信号终止进程。
老规矩,接下来上码:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
int childProcessId = -1;
int client_sockfd;
void sigint(int);
void sigint(int signal)
{
if(SIGINT == signal)
{
qDebug() << "My DADDY has Killed me!!!";
exit(0);
}
}
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
//tcp server
processServer = new QTcpServer();
connect(processServer, SIGNAL(newConnection()),
this, SLOT(slot_recvClientConnect()));
if(!processServer->listen(QHostAddress::Any, 8866))
{
// 监听本地主机的 88 66 端口,如果出错就输出错误信息,并关闭
qDebug() <<"error message"<
processServer->close();
}
///////////////client
struct sockaddr_in remote_addr; // 服务器端网络地址结构体
memset(&remote_addr,0,sizeof(remote_addr)); // 数据初始化 -- 清零
remote_addr.sin_family=AF_INET; // 设置为 IP 通信
remote_addr.sin_addr.s_addr=inet_addr("127.0.0.1");// 服务器 IP 地址
remote_addr.sin_port=htons(8866); // 服务器端口号
/* 创建客户端套接字 --IPv4 协议,面向连接通信, TCP 协议 */
if((client_sockfd=socket(PF_INET,SOCK_STREAM,0))<0)
{
perror("socket");
return;
}
/* 将套接字绑定到服务器的网络地址上 */
if(::connect(client_sockfd,(struct sockaddr *)&remote_addr,sizeof(struct sockaddr))<0)
{
perror("connect");
return;
}
}
MainWindow::~MainWindow()
{
processServer->close();
delete ui;
delete processServer;
}
void MainWindow::slot_recvClientConnect()
{
qDebug() << "accept connect";
clientConnect = processServer->nextPendingConnection();
connect(clientConnect, SIGNAL(readyRead()),
this, SLOT(slot_readClientData()));
}
void MainWindow::slot_readClientData()
{
QString str;
str = clientConnect->readAll();
clientConnect->write("hello");
qDebug() << "client data>>:" << str ;
}
void MainWindow::on_pbn_start_clicked()
{
pid_t pid;
pid = fork();
if(pid < 0)
{
qDebug() << "creat process faild!";
}
else if((pid_t)0 == pid) //child process,pid is child pid
{
signal(SIGINT, sigint);
qDebug() << "this is client proccess!";
char buf1[] = "socket client";
while(1)
{
send(client_sockfd,buf1,strlen(buf1),0);
QThread::sleep(3);
}
}
else // parent process
{
childProcessId = pid;
qDebug() << "child process pid is " << childProcessId;
}
}
void MainWindow::on_pbn_stop_clicked()
{
if(-1 != childProcessId)
{
pid_t pidClear;
kill(childProcessId, SIGINT);
QThread::usleep(500);
do{
pidClear = waitpid(childProcessId,NULL,WNOHANG);
if(-1 == pidClear)
{
qDebug() << "clear error!!!";
}
if(childProcessId == pidClear)
{
qDebug() << "clear success!!!";
}
QThread::usleep(500);
}while(0 == pidClear);
childProcessId = -1;
}
}
程序环境是ubuntu + Qt。
简单介绍下程序的主体构成:构造函数中使用c创建客户端,使用 Qt 的类创建服务器。
界面点击 start 按钮时,使用 fork 创建子进程,在进程中客户端向服务器发送数据。点击 stop 按钮时,父进程向子进程发出 kill 信号,由于子进程注册了中断信号,所以会执行信号函数中的操作。之后父进程使用 waitpid(childProcessId,NULL,WNOHANG) 等待清理子进程,之后进程资源被释放。如果 python 解释器运行在进程中,那么 python 解释器也会被中断,资源被清理故而不会被占用。 Python 重定向信息输出也可通过 socket 发送出来。
程序运行效果:
在子进程被中断前,先进入信号函数。之后由父进程清理子进程资源。
如果大家觉得还阔以,欢迎大家后台留言交流。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- [译] 在多进程应用中使用 WorkManager
- 为什么 Redis 快照使用子进程
- Laravel 使用 Supervisor 开启多个进程处理队列
- 使用 Visual Studio 调试多进程的程序
- PHP的Pcntl多进程扩展基础使用
- PM2 进程管理工具使用总结
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
数据结构与算法分析
[美]Mark Allen Weiss / 张怀勇 / 人民邮电出版社 / 2007年 / 49.00元
《数据结构与算法分析:C++描述(第3版)》是数据结构和算法分析的经典教材,书中使用主流的程序设计语言C++作为具体的实现语言。书的内容包括表、栈、队列、树、散列表、优先队列、排序、不相交集算法、图论算法、算法分析、算法设计、摊还分析、查找树算法、k-d树和配对堆等。《数据结构与算法分析:C++描述(第3版)》适合作为计算机相关专业本科生的数据结构课程和研究生算法分析课程的教材。本科生的数据结构课......一起来看看 《数据结构与算法分析》 这本书的介绍吧!