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 接口类与抽象类的实际作用
Nov 26 PHP
php 面向对象的一个例子
Apr 12 PHP
基于PHPExcel的常用方法总结
Jun 13 PHP
ThinkPHP分页类使用详解
Mar 05 PHP
ThinkPHP打开验证码页面显示乱码的解决方法
Dec 18 PHP
PHP查找数值数组中不重复最大和最小的10个数的方法
Apr 20 PHP
php实现过滤字符串中的中文和数字实例
Jul 29 PHP
Yii2增删改查之查询 where参数详细介绍
Aug 08 PHP
php使用Jpgraph创建折线图效果示例
Feb 15 PHP
yii2 url重写并隐藏index.php方法
Dec 10 PHP
让whoops帮我们告别ThinkPHP6的异常页面
Mar 02 PHP
Thinkphp5+Redis实现商品秒杀代码实例讲解
Dec 29 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 5.0对象模型深度探索之属性和方法
2008/03/27 PHP
又一个php 分页类实现代码
2009/12/03 PHP
php set_magic_quotes_runtime() 函数过时解决方法
2010/07/08 PHP
php中的Base62类(适用于数值转字符串)
2013/08/12 PHP
PHP程序员必须清楚的问题汇总
2014/12/18 PHP
基于JQuery的浮动DIV显示提示信息并自动隐藏
2011/02/11 Javascript
Extjs优化(一)删除冗余代码提高运行速度
2013/04/15 Javascript
Javascript全局变量var与不var的区别深入解析
2013/12/09 Javascript
jquery+ajax实现跨域请求的方法
2015/01/20 Javascript
JavaScript的Date()方法使用详解
2015/06/09 Javascript
ES6中如何使用Set和WeakSet
2016/03/10 Javascript
AngularJS压缩JS技巧分析
2016/11/08 Javascript
js中DOM三级列表(代码分享)
2017/03/20 Javascript
vue如何从接口请求数据
2017/06/22 Javascript
Vue结合后台导入导出Excel问题详解
2019/02/19 Javascript
微信小程序-form表单提交代码实例
2019/04/29 Javascript
JS中的算法与数据结构之二叉查找树(Binary Sort Tree)实例详解
2019/08/16 Javascript
关于layui toolbar和template的结合使用方法
2019/09/19 Javascript
[03:04]DOTA2英雄基础教程 影魔
2013/12/11 DOTA
[01:05]主宰至宝剑心之遗
2017/03/16 DOTA
[56:42]VP vs RNG 2019国际邀请赛小组赛 BO2 第二场 8.15
2019/08/17 DOTA
python小技巧之批量抓取美女图片
2014/06/06 Python
python语言使用技巧分享
2016/05/31 Python
对Python中的@classmethod用法详解
2018/04/21 Python
python正则爬取某段子网站前20页段子(request库)过程解析
2019/08/10 Python
Python GUI编程学习笔记之tkinter中messagebox、filedialog控件用法详解
2020/03/30 Python
用Python在Excel里画出蒙娜丽莎的方法示例
2020/04/28 Python
Python中pass的作用与使用教程
2020/11/13 Python
CSS3属性使网站设计增强同时不消弱可用性
2009/08/29 HTML / CSS
纯CSS3实现自定义Tooltip边框涂鸦风格的教程
2014/11/05 HTML / CSS
html5小程序飞入购物车(抛物线绘制运动轨迹点)
2020/10/19 HTML / CSS
萨克斯第五大道的折扣店:Saks Fifth Avenue OFF 5TH
2016/08/25 全球购物
高一自我鉴定
2013/12/17 职场文书
开工仪式策划方案
2014/05/23 职场文书
公司新人试用期自我评价
2014/09/17 职场文书
python如何利用cv2.rectangle()绘制矩形框
2022/12/24 Python