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入门的学习方法
Jan 02 PHP
php 中文处理函数集合
Aug 27 PHP
PHP学习之正则表达式
Apr 17 PHP
php 批量替换程序的具体实现代码
Oct 04 PHP
php通过Chianz.com获取IP地址与地区的方法
Jan 14 PHP
php创建桌面快捷方式实现方法
Dec 31 PHP
Laravel中间件实现原理详解
Oct 09 PHP
php修改数组键名的方法示例
Apr 15 PHP
PHP中散列密码的安全性分析
Jul 26 PHP
浅谈thinkphp的nginx配置,以及重写隐藏index.php入口文件方法
Oct 12 PHP
php设计模式之抽象工厂模式分析【星际争霸游戏案例】
Jan 23 PHP
PHP论坛实现积分系统的思路代码详解
Jun 01 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获取网址的顶级域名函数代码
2012/09/24 PHP
PHP双向链表定义与用法示例
2018/01/31 PHP
页面中js执行顺序
2009/11/09 Javascript
JQuery 1.6发布 性能提升,同时包含大量破坏性变更
2011/05/10 Javascript
浅析offsetLeft,Left,clientLeft之间的区别
2013/11/30 Javascript
jquery插件tooltipv顶部淡入淡出效果使用示例
2013/12/05 Javascript
Jquery实现的一种常用高亮效果示例代码
2014/01/28 Javascript
jQuery实现切换字体大小的方法
2015/03/10 Javascript
超级给力的JavaScript的React框架入门教程
2015/07/02 Javascript
JavaScript计算某一天是星期几的方法
2015/08/05 Javascript
jQuery DataTables插件自定义Ajax分页实例解析
2020/04/28 Javascript
Node.js包管理器Yarn的入门介绍与安装
2016/10/17 Javascript
mongoose中利用populate处理嵌套的方法
2017/05/26 Javascript
JS实现图片放大镜插件详解
2017/11/06 Javascript
基于Bootstrap实现城市三级联动
2017/11/23 Javascript
JavaScript实现多叉树的递归遍历和非递归遍历算法操作示例
2018/02/08 Javascript
vue2.0 自定义 饼状图 (Echarts)组件的方法
2018/03/02 Javascript
node版本管理工具n包使用教程详解
2018/11/09 Javascript
详解vue路由篇(动态路由、路由嵌套)
2019/01/27 Javascript
vue在自定义组件中使用v-model进行数据绑定的方法
2019/03/25 Javascript
[50:15]VP vs Mineski 2018国际邀请赛淘汰赛BO3 第二场 8.22
2018/08/23 DOTA
10种检测Python程序运行时间、CPU和内存占用的方法
2015/04/01 Python
Python类的继承和多态代码详解
2017/12/27 Python
Python简单实现的代理服务器端口映射功能示例
2018/04/08 Python
Django框架文件上传与自定义图片上传路径、上传文件名操作分析
2019/05/10 Python
Python自带的IDE在哪里
2020/07/01 Python
详解如何在css3打包后自动追加前缀插件:autoprefixer
2018/12/18 HTML / CSS
十一个高级MySql面试题
2014/10/06 面试题
会计专业大学生求职信范文
2014/01/28 职场文书
学校安全生产承诺书
2014/05/23 职场文书
纪念九一八事变演讲稿:忘记意味着背叛
2014/09/14 职场文书
董事长岗位职责
2015/02/13 职场文书
如何书写读后感?(附范文)
2019/07/26 职场文书
Go 语言下基于Redis分布式锁的实现方式
2021/06/28 Golang
mybatis源码解读之executor包语句处理功能
2022/02/15 Java/Android
动视暴雪取消疫苗禁令 让所有员工返回线下工作
2022/04/03 其他游戏