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之第一天
Oct 09 PHP
php框架Phpbean说明
Jan 10 PHP
PHP简单系统数据添加以及数据删除模块源文件下载
Jun 07 PHP
PHP PDO函数库详解
Apr 27 PHP
解决File size limit exceeded 错误的方法
Jun 14 PHP
php遍历文件夹下的所有文件和子文件夹示例
Mar 20 PHP
yii,CI,yaf框架+smarty模板使用方法
Dec 29 PHP
PHP模板引擎Smarty自定义变量调解器用法
Apr 11 PHP
py文件转exe时包含paramiko模块出错解决方法
Aug 12 PHP
PHP简单获取上月、本月、近15天、近30天的方法示例
Jul 03 PHP
Yii使用EasyWechat实现小程序获取用户的openID的方法
Apr 29 PHP
PHP实现简易图形计算器
Aug 28 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
动态新闻发布的实现及其技巧
2006/10/09 PHP
php 各种应用乱码问题的解决方法
2010/05/09 PHP
PHP的伪随机数与真随机数详解
2015/05/27 PHP
PHP检查端口是否可以被绑定的方法示例
2018/08/09 PHP
php curl获取https页面内容,不直接输出返回结果的设置方法
2019/01/15 PHP
Laravel框架实现的使用smtp发送邮件功能示例
2019/03/12 PHP
解读IE和firefox下JScript和HREF的执行顺序
2008/01/12 Javascript
javascript 写类方式之六
2009/07/05 Javascript
javaScript让文本框内的最后一个文字的后面获得焦点实现代码
2013/01/06 Javascript
JS判断数组中是否有重复值得三种实用方法
2013/08/16 Javascript
Jquery 实现表格颜色交替变化鼠标移过颜色变化实例
2013/08/28 Javascript
jQuery实现的进度条效果
2015/07/15 Javascript
利用jquery制作滚动到指定位置触发动画
2016/03/26 Javascript
BootStrap点击下拉菜单项后显示一个新的输入框实现代码
2016/05/16 Javascript
AngularJS基础 ng-submit 指令简单示例
2016/08/03 Javascript
JavaScript 中有关数组对象的方法(详解)
2016/08/15 Javascript
浅谈javascript中的Function和Arguments
2016/08/30 Javascript
Angularjs中controller的三种写法分享
2016/09/21 Javascript
整理关于Bootstrap表单的慕课笔记
2017/03/29 Javascript
jQuery Validate格式验证功能实例代码(包括重名验证)
2017/07/18 jQuery
详解JS数值Number类型
2018/02/07 Javascript
微信小程序new Date()方法失效问题解决方法
2019/07/29 Javascript
JS sort排序详细使用方法示例解析
2020/09/27 Javascript
python字典快速保存于读取的方法
2018/03/23 Python
Python利用公共键如何对字典列表进行排序详解
2018/05/19 Python
python3第三方爬虫库BeautifulSoup4安装教程
2018/06/19 Python
在django admin中添加自定义视图的例子
2019/07/26 Python
Python如何获取Win7,Win10系统缩放大小
2020/01/10 Python
python中导入 train_test_split提示错误的解决
2020/06/19 Python
描述Cookie和Session的作用,区别和各自的应用范围,Session工作原理
2015/03/25 面试题
新学期家长寄语
2014/01/19 职场文书
幼儿园教师师德表现自我评价
2015/03/05 职场文书
话题作文之成长
2019/12/09 职场文书
Mysql - 常用函数 每天积极向上
2021/04/05 MySQL
redis哨兵常用命令和监控示例详解
2021/05/27 Redis
vue中的可拖拽宽度div的实现示例
2022/04/08 Vue.js