PHP中的socket_read和socket_recv区别详解


Posted in PHP onFebruary 09, 2015

前几天用PHP写一个socket网络服务,在文档里看到socket_read和socket_recv这两个方法时有点晕,乍一看这不是一样的嘛,干吗还要给两个不同的用法呢。看文档没看太明白,看了下源码才搞清楚,在这里记录一下。

先看一下这两个函数的声明:

string socket_read ( resource $socket , int $length [, int $type = PHP_BINARY_READ ] )

int socket_recv ( resource $socket , string &$buf , int $len , int $flags )

可以看到,从声明可以看到,一个是把收到的数据通过执行结果返回,另一个是把收到的数据通过引用的形式返回。另一个区别就是,socket_read多了一个type,socket_recv多了一个flags(够混乱的)。我们先来看看socket_recv的源码吧!
PHP_FUNCTION(socket_recv)

{

    zval        *php_sock_res, *buf;

    char        *recv_buf;

    php_socket  *php_sock;

    int         retval;

    long        len, flags;
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rzll", &php_sock_res, &buf, &len, &flags) == FAILURE) {

        return;

    }
    ZEND_FETCH_RESOURCE(php_sock, php_socket *, &php_sock_res, -1, le_socket_name, le_socket);
    /* overflow check */

    if ((len + 1) < 2) {

        RETURN_FALSE;

    }
    recv_buf = emalloc(len + 1);

    memset(recv_buf, 0, len + 1);
    if ((retval = recv(php_sock->bsd_socket, recv_buf, len, flags)) < 1) {

        efree(recv_buf);
        zval_dtor(buf);

        Z_TYPE_P(buf) = IS_NULL;

    } else {

        recv_buf[retval] = '\0';
        /* Rebuild buffer zval */

        zval_dtor(buf);
        Z_STRVAL_P(buf) = recv_buf;

        Z_STRLEN_P(buf) = retval;

        Z_TYPE_P(buf) = IS_STRING;

    }
    if (retval == -1) {

        PHP_SOCKET_ERROR(php_sock, "unable to read from socket", errno);

        RETURN_FALSE;

    }
    RETURN_LONG(retval);

}

????乱淮蠖眩?涫涤幸恍凶罟丶??br />

if ((retval = recv(php_sock->bsd_socket, recv_buf, len, flags)) < 1) {

可以看到,实际上这个函数就是调用了系统的recv而已,只是把输入参数和得到的结果都处理了一下,比较好理解。那我们再来看下socket_read,socket_read比系统的recv函数多了一个$type参数,这也是我认为这个函数存在的意义,从文档里可以看到,type有两个值,分别是PHP_BINARY_READ和PHP_NORMAL_READ,文档里有写,PHP_BINARY_READ表示直接用系统的recv方法,PHP_NORMAL_READ表示会一读,直到遇到\n 或者 \r,我们来看下源码:
//省略一大堆

if (type == PHP_NORMAL_READ) {

    retval = php_read(php_sock, tmpbuf, length, 0);

} else {

    retval = recv(php_sock->bsd_socket, tmpbuf, length, 0);

}

可以看到,如果是PHP_NORMAL_READ模式,其实行为和socket_recv是一样的,都是用的系统的recv函数,但是如果是PHP_NORMAL_READ,则有很大区别,用了自己实现的php_read函数,那这个php_read是干啥的呢?我们继续看源码:
*t = '\0';

while (*t != '\n' && *t != '\r' && n < maxlen) {

    if (m > 0) {

        t++;

        n++;

    } else if (m == 0) {

        no_read++;

        if (nonblock && no_read >= 2) {

            return n;

            /* The first pass, m always is 0, so no_read becomes 1

             * in the first pass. no_read becomes 2 in the second pass,

             * and if this is nonblocking, we should return.. */

        }
        if (no_read > 200) {

            set_errno(ECONNRESET);

            return -1;

        }

    }
    if (n < maxlen) {

        m = recv(sock->bsd_socket, (void *) t, 1, flags);

    }
    if (errno != 0 && errno != ESPIPE && errno != EAGAIN) {

        return -1;

    }
    set_errno(0);

}

还是指copy了关键部分,可以看到,这里的实现是一直循环调用recv,直到遇到\r或者\n或者读的数据长度到了指定的maxlen。

虽然这两个函数比较混乱,但是看到这里应该明白了吧!好了睡觉去啦!

PHP 相关文章推荐
用PHP的ob_start() 控制您的浏览器cache
Aug 03 PHP
php递归删除目录下的文件但保留的实例分享
May 10 PHP
php使用cookie保存登录用户名的方法
Jan 26 PHP
php数组添加与删除单元的常用函数实例分析
Feb 16 PHP
WordPress中编写自定义存储字段的相关PHP函数解析
Dec 25 PHP
php简单实现批量上传图片的方法
May 09 PHP
利用PHP生成静态html页面的原理
Sep 30 PHP
PHP实现原生态图片上传封装类方法
Nov 08 PHP
PHP数据库操作三:redis用法分析
Aug 16 PHP
PHP多进程通信-消息队列使用
Mar 08 PHP
php探针使用原理和技巧讲解
Sep 17 PHP
用php定义一个数组最简单的方法
Oct 04 PHP
支持png透明图片的php生成缩略图类分享
Feb 08 #PHP
基于GD2图形库的PHP生成图片缩略图类代码分享
Feb 08 #PHP
php中get_object_vars()方法用法实例
Feb 08 #PHP
php面向对象中static静态属性与方法的内存位置分析
Feb 08 #PHP
php面向对象中static静态属性和静态方法的调用
Feb 08 #PHP
php延迟静态绑定实例分析
Feb 08 #PHP
PHP调用Linux命令权限不足问题解决方法
Feb 07 #PHP
You might like
PHP+Ajax检测用户名或邮件注册时是否已经存在实例教程
2014/08/23 PHP
PHP面向对象多态性实现方法简单示例
2017/09/27 PHP
PHP命名空间与自动加载机制的基础介绍
2019/08/25 PHP
Display SQL Server Login Mode
2007/06/21 Javascript
JavaScript中的typeof操作符用法实例
2014/04/05 Javascript
Javascript基础教程之break和continue语句
2015/01/18 Javascript
jQuery实现锚点scoll效果实例分析
2015/03/10 Javascript
JavaScript实现自动变换表格边框颜色
2015/05/08 Javascript
JavaScript通过HTML的class来获取HTML元素的方法总结
2016/05/24 Javascript
ES6所改良的javascript“缺陷”问题
2016/08/23 Javascript
浅析BootStrap中Modal(模态框)使用心得
2016/12/24 Javascript
JQuery 选择器、DOM节点操作练习实例
2017/09/28 jQuery
详解如何去除vue项目中的#——History模式
2017/10/13 Javascript
在vue 中使用 less的教程详解
2018/09/26 Javascript
详解微信小程序入门从这里出发(登录注册、开发工具、文件及结构介绍)
2020/07/21 Javascript
js实现有趣的倒计时效果
2021/01/19 Javascript
[04:19]DOTA2完美大师赛第四天精彩集锦
2017/11/26 DOTA
零基础写python爬虫之爬虫编写全记录
2014/11/06 Python
python实现可以断点续传和并发的ftp程序
2016/09/13 Python
利用Pandas 创建空的DataFrame方法
2018/04/08 Python
pyshp创建shp点文件的方法
2018/12/31 Python
基于python2.7实现图形密码生成器的实例代码
2019/11/05 Python
Python try except else使用详解
2021/01/12 Python
Otticanet意大利:最顶尖的世界名牌眼镜, 能得到打折季的价格
2019/03/10 全球购物
日期和时间问题
2015/01/04 面试题
家居装修公司创业计划书范文
2014/03/20 职场文书
捐款倡议书格式范文
2014/05/14 职场文书
搞笑婚前保证书
2015/02/28 职场文书
小区保洁员岗位职责
2015/04/10 职场文书
2015年财务人员个人工作总结
2015/07/27 职场文书
商业计划书之服装
2019/09/09 职场文书
创业计划书之酒吧
2019/12/02 职场文书
Django给表单添加honeypot验证增加安全性
2021/05/06 Python
浅谈Python协程asyncio
2021/06/20 Python
如何解决php-fpm启动不了问题
2021/11/17 PHP
HTML5中的DOCUMENT.VISIBILITYSTATE属性详解
2023/05/07 HTML / CSS