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入门学习知识点六 PHP文件的读写操作代码
Jul 14 PHP
php继承的一个应用
Sep 06 PHP
深入理解用mysql_fetch_row()以数组的形式返回查询结果
Jun 05 PHP
解析PHP中的file_get_contents获取远程页面乱码的问题
Jun 25 PHP
PHP生成sitemap.xml地图函数
Nov 13 PHP
PHP登陆后跳转到登陆前页面实现思路及代码
Jan 17 PHP
ThinkPHP提示错误Fatal error: Allowed memory size的解决方法
Feb 12 PHP
php函数mkdir实现递归创建层级目录
Oct 27 PHP
php实现头像上传预览功能
Apr 27 PHP
php探针不显示内存解决方法
Sep 17 PHP
laravel 判断查询数据库返回值的例子
Oct 11 PHP
laravel5 Eloquent 实现事务方式
Oct 21 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
main.php
2006/12/09 PHP
Excel数据导入Mysql数据库的实现代码
2008/06/05 PHP
将博客园(cnblogs.com)数据导入到wordpress的代码
2013/01/06 PHP
php对二维数组进行相关操作(排序、转换、去空白等)
2015/11/04 PHP
Laravel中日期时间处理包Carbon的简单使用
2017/09/21 PHP
一文看懂PHP进程管理器php-fpm
2020/06/01 PHP
js Flash插入函数免激活代码
2009/03/31 Javascript
JavaScript实现的日期控件具体代码
2013/11/18 Javascript
jquery移除、绑定、触发元素事件使用示例详解
2014/04/10 Javascript
Javascript中arguments对象详解
2014/10/22 Javascript
angularjs 源码解析之scope
2016/08/22 Javascript
js图片上传前预览功能(兼容所有浏览器)
2016/08/24 Javascript
KnockoutJS 3.X API 第四章之数据控制流with绑定
2016/10/10 Javascript
javascript使用btoa和atob来进行Base64转码和解码
2017/03/20 Javascript
JS实现自动轮播图效果(自适应屏幕宽度+手机触屏滑动)
2017/06/19 Javascript
angularJs的ng-class切换class
2017/06/23 Javascript
使用原生js封装的ajax实例(兼容jsonp)
2017/10/12 Javascript
解决angularjs WdatePicker ng-model的问题
2018/09/13 Javascript
微信小程序实现购物车代码实例详解
2019/08/29 Javascript
微信小程序开发中var that =this的用法详解
2020/01/18 Javascript
[38:41]2014 DOTA2国际邀请赛中国区预选赛 LGD VS CNB
2014/05/22 DOTA
[01:33:07]VGJ.T vs Newbee Supermajor 败者组 BO3 第一场 6.6
2018/06/07 DOTA
使用rst2pdf实现将sphinx生成PDF
2016/06/07 Python
Python实现输出某区间范围内全部素数的方法
2018/05/02 Python
分析经典Python开发工程师面试题
2019/04/08 Python
Django中使用session保持用户登陆连接的例子
2019/08/06 Python
Python中pymysql 模块的使用详解
2019/08/12 Python
python3的url编码和解码,自定义gbk、utf-8的例子
2019/08/22 Python
python+selenium 点击单选框-radio的实现方法
2019/09/03 Python
PyTorch预训练Bert模型的示例
2020/11/17 Python
洛杉矶生活休闲而精致的基础品牌:Mika Jaymes
2018/01/07 全球购物
经典演讲稿范文
2013/12/30 职场文书
致400米运动员广播稿
2014/02/07 职场文书
小学生个人先进事迹材料
2014/05/08 职场文书
四风剖析查摆对照检查材料思想汇报
2014/09/24 职场文书
详解CSS不受控制的position fixed
2021/05/25 HTML / CSS