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公用函数列表[正则]
Feb 22 PHP
php 文章采集正则代码
Dec 28 PHP
php中DOMDocument简单用法示例代码(XML创建、添加、删除、修改)
Dec 19 PHP
解析MySql与Java的时间类型
Jun 22 PHP
浅析PHP绘图技术
Jul 03 PHP
php curl post 时出现的问题解决
Jan 30 PHP
php使用wordwrap格式化文本段落的方法
Mar 17 PHP
ThinkPHP开发框架函数详解:C方法
Aug 14 PHP
PHP程序员的技术成长规划
Mar 25 PHP
PHP数学运算与数据处理实例分析
Apr 01 PHP
php四种定界符详解
Feb 16 PHP
关于laravel5.5的定时任务详解(demo)
Oct 23 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
dede3.1分页文字采集过滤规则详说(图文教程)续二
2007/04/03 PHP
php接口与接口引用的深入解析
2013/08/09 PHP
PHP动态生成指定大小随机图片的方法
2016/03/25 PHP
Yii2创建多界面主题(Theme)的方法
2016/10/08 PHP
php文件上传原理与实现方法详解
2019/12/20 PHP
使用原生javascript创建通用表单验证——更锋利的使用dom对象
2011/09/13 Javascript
jQuery学习笔记(1)--用jQuery实现异步通信(用json传值)具体思路
2013/04/08 Javascript
jquery实现div拖拽宽度示例代码
2013/07/31 Javascript
Jquery的hover方法让鼠标经过li时背景变色
2013/09/06 Javascript
利用cookie记住背景颜色示例代码
2013/11/04 Javascript
JavaScript插件化开发教程 (二)
2015/01/27 Javascript
用js编写的简单的计算器代码程序
2015/08/04 Javascript
Flow之一个新的Javascript静态类型检查器
2015/12/21 Javascript
浅析AngularJS中的指令
2016/03/20 Javascript
基于javascript实现全屏漂浮广告
2016/03/31 Javascript
全面解析DOM操作和jQuery实现选项移动操作代码分享
2016/06/07 Javascript
angular十大常见问题
2017/03/07 Javascript
layui中layer前端组件实现图片显示功能的方法分析
2017/10/13 Javascript
详解vuex 渐进式教程实例代码
2018/11/27 Javascript
js实现移动端图片滑块验证功能
2020/09/29 Javascript
原生js实现表格翻页和跳转
2020/09/29 Javascript
vue 递归组件的简单使用示例
2021/01/14 Vue.js
使用python实现BLAST
2018/02/12 Python
numpy.where() 用法详解
2019/05/27 Python
python with语句的原理与用法详解
2020/03/30 Python
解决Pytorch自定义层出现多Variable共享内存错误问题
2020/06/28 Python
Python DES加密实现原理及实例解析
2020/07/17 Python
用Python 执行cmd命令
2020/12/18 Python
美国著名的品牌折扣店:Burlington
2017/06/08 全球购物
size?瑞典:英国伦敦的球鞋精品店
2018/03/01 全球购物
英国在线玫瑰专家:InterRose
2019/12/01 全球购物
Belstaff英国官方在线商店:Belstaff.co.uk
2021/02/09 全球购物
建设工程授权委托书
2014/09/22 职场文书
敲诈同学钱财检讨书范文
2014/11/18 职场文书
2015年清明节网上祭英烈活动总结
2015/03/26 职场文书
飞越疯人院观后感
2015/06/09 职场文书