IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> Linux下php环境dio_read读取串口出现内存溢出的解决办法 -> 正文阅读

[系统运维]Linux下php环境dio_read读取串口出现内存溢出的解决办法

上篇内容介绍了在Linux环境下可以通过PHP的dio模块实现串口数据采集

CentOS Linux下使用PHP实现串口通信(serial)_zgh419566的博客-CSDN博客

为此我特定编写了服务程序,但是发现服务运行一段时间会异常退出

经排查系统报错 "Fatal Error: Allowed memory size of xxxxxx bytes exhausted"

通过跟踪问题,发现php_dio函数存在内存溢出现象

通过研究别人写的程序??tty_uart.c??https://github.com/WCHSoftGroup/tty_uart

/**
 * libtty_read - read data from uart
 * @fd: file descriptor of tty device
 *
 * The function return the number of bytes read if success, others if fail.
 */
static int libtty_read(int fd)
{
	int nwrite, nread;
	char buf[1024];
	int i;
	
	nread = read(fd, buf, sizeof(buf));
	if (nread >= 0) {
		if (newLine) { printf("\n************************* read nread %d bytes.\n", nread); }
	} else {
		printf("read error: %d\n", nread);
		return nread;
	}

	if (verbose) {
		for (i = 0; i < nread; i++){
			printf("%.2x", (uint8_t)buf[i]);
		}
	}

	return nread;
}

而php_dio官方代码是

/* {{{ proto string dio_read(resource fd[, int n])
   Read n bytes from fd and return them, if n is not specified, read 1k */
PHP_FUNCTION(dio_read)
{
	zval     *r_fd;
	php_fd_t *f;
	char     *data;
	zend_long      bytes = 1024;
	ssize_t   res;

	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|l", &r_fd, &bytes) == FAILURE) {
		return;
	}

	if ((f = (php_fd_t *) zend_fetch_resource(Z_RES_P(r_fd), le_fd_name, le_fd)) == NULL) {
		RETURN_FALSE;
	}

	if (bytes <= 0) {
		php_error_docref(NULL, E_WARNING, "Length parameter must be greater than 0.");
		RETURN_FALSE;
	}

	data = emalloc(bytes + 1);
	res = read(f->fd, data, bytes);
	if (res <= 0) {
		efree(data);
		RETURN_NULL();
	}

	data = erealloc(data, res + 1);
	data[res] = 0;

	RETURN_STRINGL(data, res);
	efree(data);
}
/* }}} */

明显的看见官方的php_dio存在内存分配问题,怀疑这里有BUG

于是照着tty_uart的代码做了一些修改:

/* {{{ proto string dio_read(resource fd[, int n])
   Read n bytes from fd and return them, if n is not specified, read 1k */
PHP_FUNCTION(dio_read)
{
	zval     *r_fd;
	php_fd_t *f;
	char     data[4096];
	zend_long      bytes = 1024;
	ssize_t   res;

	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|l", &r_fd, &bytes) == FAILURE) {
		return;
	}

	if ((f = (php_fd_t *) zend_fetch_resource(Z_RES_P(r_fd), le_fd_name, le_fd)) == NULL) {
		RETURN_FALSE;
	}

	if (bytes <= 0) {
		php_error_docref(NULL, E_WARNING, "Length parameter must be greater than 0.");
		RETURN_FALSE;
	}

	//data = emalloc(bytes + 1);
	res = read(f->fd, data, bytes);
	if (res <= 0) {
		//efree(data);
		RETURN_NULL();
	}

	//data = erealloc(data, res + 1);
	//data[res] = 0;

	RETURN_STRINGL(data, res);
	//efree(data);
}
/* }}} */

经过几天的运行,PHP程序一直能够稳定的读取串口数据,并且内存占用率一直保存在1460KB左右,非常的稳定。

?备注:通过研究,CentOS?LInux内核默认只对串口保存4096字符的内容,因此我们的程序读取数据也设置最大读取 4096字节(翻倍,为了稳定)。

在此将稳定的代码放出来给大家使用。

dio-0.2.0_解决dio_read内存溢出问题-其它文档类资源-CSDN下载

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2021-12-07 12:25:39  更:2021-12-07 12:27:15 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/16 3:22:17-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码