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中使用与Perl兼容的正则表达式
Nov 26 PHP
PHP 删除一个目录及目录下的所有文件的函数代码
May 26 PHP
PHP读取数据库并按照中文名称进行排序实现代码
Jan 29 PHP
php 使用GD库为页面增加水印示例代码
Mar 24 PHP
PHP实现对文本数据库的常用操作方法实例演示
Jul 04 PHP
destoon实现VIP排名一直在前面排序的方法
Aug 21 PHP
php实现的简单日志写入函数
Mar 31 PHP
ThinkPHP静态缓存简单配置和使用方法详解
Mar 23 PHP
php创建图像具体步骤
Mar 13 PHP
php编程实现简单的网页版计算器功能示例
Apr 26 PHP
浅谈PHP中pack、unpack的详细用法
Mar 12 PHP
thinkphp5 框架结合plupload实现图片批量上传功能示例
Apr 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 error_log()将错误信息写入一个文件(定义和用法)
2013/10/25 PHP
smarty中改进truncate使其支持中文的方法
2016/05/30 PHP
解决PhpStorm64不能启动的问题
2020/06/20 PHP
div层的移动及性能优化
2010/11/16 Javascript
动态创建样式表在各浏览器中的差异测试代码
2011/09/13 Javascript
Jquery UI震动效果实现原理及步骤
2013/02/04 Javascript
JS保留小数点(四舍五入、四舍六入)实现思路及实例
2013/04/25 Javascript
JavaScript调用后台的三种方法实例
2013/10/17 Javascript
JavaScript中string转换成number介绍
2014/12/31 Javascript
JS实现固定在右下角可展开收缩DIV层的方法
2015/02/13 Javascript
JavaScript手机振动API
2016/06/11 Javascript
vue组件生命周期详解
2017/11/07 Javascript
详解搭建es6+devServer简单开发环境
2018/09/25 Javascript
javascript实现留言板功能
2020/02/08 Javascript
原生JS实现拖拽效果
2020/12/04 Javascript
Python里隐藏的“禅”
2014/06/16 Python
Python遍历目录并批量更换文件名和目录名的方法
2016/09/19 Python
python3+PyQt5泛型委托详解
2018/04/24 Python
python学生管理系统
2019/01/30 Python
python3.5的包存放的具体路径
2020/08/16 Python
英国曼彻斯特宠物用品品牌:Bunty Pet Products
2019/07/27 全球购物
军用级手机壳,专为冒险而建:Zizo Wireless
2019/08/07 全球购物
大学四年规划书范文
2013/12/27 职场文书
会计工作心得体会
2014/01/13 职场文书
大学班级干部的自我评价分享
2014/02/10 职场文书
大学军训感想
2014/02/12 职场文书
百日安全生产活动总结
2014/07/05 职场文书
培训师岗位职责
2015/02/14 职场文书
2015年社区综治宣传月活动总结
2015/03/25 职场文书
2015小学教育教学工作总结
2015/07/21 职场文书
学风建设主题班会
2015/08/17 职场文书
妇联2016年六一国际儿童节活动总结
2016/04/06 职场文书
导游词之云南丽江古城
2019/09/17 职场文书
聊聊SpringBoot自动装配的魔力
2021/11/17 Java/Android
浅谈Redis跟MySQL的双写问题解决方案
2022/02/24 Redis
分享3个非常实用的 Python 模块
2022/03/03 Python