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 相关文章推荐
Classes and Objects in PHP5-面向对象编程 [1]
Oct 09 PHP
PHP中for与foreach的区别分析
Mar 09 PHP
php学习之流程控制实现代码
Jun 09 PHP
PHP中去除换行解决办法小结(PHP_EOL)
Nov 27 PHP
比较strtr, str_replace和preg_replace三个函数的效率
Jun 26 PHP
使用PHP获取汉字的拼音(全部与首字母)
Jun 27 PHP
php使用反射插入对象示例分享
Mar 11 PHP
ThinkPHP3.1新特性之G方法的使用
Jun 19 PHP
php中substr()函数参数说明及用法实例
Nov 15 PHP
PHP模拟QQ登录的方法
Jul 29 PHP
Adnroid 微信内置浏览器清除缓存
Jul 11 PHP
Laravel监听数据库访问,打印SQL的例子
Oct 24 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的ob_start() 控制您的浏览器cache
2009/08/03 PHP
PHP对MongoDB[NoSQL]数据库的操作
2013/03/01 PHP
利用谷歌 Translate API制作自己的翻译脚本
2014/06/04 PHP
PHP注释语法规范与命名规范详解篇
2018/01/21 PHP
强悍无比的WEB开发好助手FireBug(Firefox Plugin)
2007/01/16 Javascript
使用jQuery的ajax功能实现的RSS Reader 代码
2009/09/03 Javascript
jquery移除、绑定、触发元素事件使用示例详解
2014/04/10 Javascript
jQuery中用dom操作替代正则表达式
2014/12/29 Javascript
javascript图片滑动效果实现
2021/01/28 Javascript
Angularjs 动态改变title标题(兼容ios)
2016/12/29 Javascript
vue-cli webpack 引入swiper的操作方法
2018/09/15 Javascript
vue 之 css module的使用方法
2018/12/04 Javascript
jquery实现商品sku多属性选择功能(商品详情页)
2019/12/20 jQuery
vue项目如何监听localStorage或sessionStorage的变化
2021/01/04 Vue.js
手动实现vue2.0的双向数据绑定原理详解
2021/02/06 Vue.js
python生成tensorflow输入输出的图像格式的方法
2018/02/12 Python
kaggle+mnist实现手写字体识别
2018/07/26 Python
详解python的argpare和click模块小结
2019/03/31 Python
python实现五子棋小程序
2019/06/18 Python
Django的性能优化实现解析
2019/07/30 Python
Python Django Cookie 简单用法解析
2019/08/13 Python
Python基于pyecharts实现关联图绘制
2020/03/27 Python
Pyqt助手安装PyQt5帮助文档过程图解
2020/11/20 Python
HTML5的一个显示电池状态的API简介
2015/06/18 HTML / CSS
中餐厅主管的职责范文
2014/02/04 职场文书
酒鬼酒广告词
2014/03/21 职场文书
条幅标语大全
2014/06/20 职场文书
学校周年庆活动方案
2014/08/22 职场文书
2014年教师思想工作总结
2014/12/03 职场文书
走进毛泽东观后感
2015/06/04 职场文书
信息技术课教学反思
2016/02/23 职场文书
Python 如何解决稀疏矩阵运算
2021/05/26 Python
Python面向对象之内置函数相关知识总结
2021/06/24 Python
深入理解java.lang.String类的不可变性
2021/06/27 Java/Android
叶县这家生产军用电台的兵工厂,人称“四机部”,走出一上将
2022/02/18 无线电
了解Kubernetes中的Service和Endpoint
2022/04/01 Servers