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中ob(Output Buffer 输出缓冲)函数使用方法
Jul 21 PHP
Thinkphp使用mongodb数据库实现多条件查询方法
Jun 26 PHP
PHP中定义数组常量(array常量)的方法
Nov 17 PHP
对PHP PDO的一些认识小结
Jan 23 PHP
php强大的时间转换函数strtotime
Feb 18 PHP
php实现微信模拟登陆、获取用户列表及群发消息功能示例
Jun 28 PHP
PHP提取字符串中的手机号正则表达式怎么写
Jul 17 PHP
PHP实现基于回溯法求解迷宫问题的方法详解
Aug 17 PHP
Laravel框架使用Seeder实现自动填充数据功能
Jun 13 PHP
Laravel框架搜索分页功能示例
Feb 01 PHP
解决Laravel自定义类引入和命名空间的问题
Oct 15 PHP
PHP扩展安装方法步骤解析
Nov 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清除数组中所有字符串两端空格的方法
2014/10/20 PHP
php堆排序实现原理与应用方法
2015/01/03 PHP
PHP按指定键值对二维数组进行排序的方法
2015/12/22 PHP
浅谈PHP正则中的捕获组与非捕获组
2016/07/18 PHP
PHP常量define和const的区别详解
2019/05/18 PHP
jQuery 1.3 和 Validation 验证插件1.5.1
2009/07/09 Javascript
jquery和javascript的区别(常用方法比较)
2013/07/04 Javascript
fckeditor粘贴Word时弹出窗口取消的方法
2014/10/30 Javascript
JavaScript使用cookie实现记住账号密码功能
2015/04/27 Javascript
javascript实现省市区三级联动下拉框菜单
2015/11/17 Javascript
jquery拖拽排序简单实现方法(效果增强版)
2016/02/16 Javascript
HTML5 canvas 9绘制图片实例详解
2016/09/06 Javascript
基于Layer+jQuery的自定义弹框
2020/05/26 Javascript
简单实现node.js图片上传
2016/12/18 Javascript
JS操作xml对象转换为Json对象示例
2017/03/25 Javascript
React中jquery引用的实现方法
2017/09/12 jQuery
详解vue项目中如何引入全局sass/less变量、function、mixin
2018/06/02 Javascript
vue新vue-cli3环境配置和模拟json数据的实例
2018/09/19 Javascript
JavaScript 对引擎、运行时、调用堆栈的概述理解
2018/10/22 Javascript
vue 自定指令生成uuid滚动监听达到tab表格吸顶效果的代码
2020/09/16 Javascript
[59:15]EG vs LGD 2018国际邀请赛淘汰赛BO3 第一场 8.26
2018/08/29 DOTA
python爬虫入门教程--优雅的HTTP库requests(二)
2017/05/25 Python
python3实现UDP协议的服务器和客户端
2017/06/14 Python
django admin添加数据自动记录user到表中的实现方法
2018/01/05 Python
python 获取文件下所有文件或目录os.walk()的实例
2018/04/23 Python
python smtplib模块自动收发邮件功能(二)
2018/05/22 Python
python如何使用Redis构建分布式锁
2020/01/16 Python
Python函数默认参数常见问题及解决方案
2020/03/26 Python
荣耀俄罗斯官网:HONOR俄罗斯
2020/10/31 全球购物
用JAVA实现一种排序,JAVA类实现序列化的方法(二种)
2014/04/23 面试题
日语专业推荐信
2013/11/12 职场文书
保安2014年终工作总结
2014/12/06 职场文书
读书笔记怎么写
2015/07/01 职场文书
民政局2016年“六一”儿童节慰问活动总结
2016/04/06 职场文书
Win11如何修改dns?Win11修改dns图文教程
2022/01/18 数码科技
TypeScript 使用 Tuple Union 声明函数重载
2022/04/07 Javascript