swoole_client源码解析之connect过程(一)

在前面一篇文章swoole源码解析之swoole_client流程解析(一)中我们介绍了swoole_client的构造函数和set函数的实现原理,这里我们结合第一篇中的demo流程继续解析余下的流程,首先我们从connect方法开始介绍。

//swoole_client对象的connect方法流程
static PHP_METHOD(swoole_client, connect)
{
    zend_long port = 0, sock_flag = 0;//分别表示连接的端口信息和socket的属性信息
    char *host = NULL;//用于连接的ip地址信息
    zend_size_t host_len;
    double timeout = SW_CLIENT_DEFAULT_TIMEOUT;//连接超时时间,默认为0.5s

    //解析php端调用时传入的参数信息,看接口文档可以看到输入参数有ip,port,socket的属性信息和connect的超时时间
#ifdef FAST_ZPP
    ZEND_PARSE_PARAMETERS_START(1, 4)
        Z_PARAM_STRING(host, host_len)
        Z_PARAM_OPTIONAL
        Z_PARAM_LONG(port)
        Z_PARAM_DOUBLE(timeout)
        Z_PARAM_LONG(sock_flag)
    ZEND_PARSE_PARAMETERS_END();
#else
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ldl", &host, &host_len, &port, &timeout, &sock_flag) == FAILURE)
    {
        return;
    }
#endif

    if (host_len <= 0)//ip地址信息异常
    {
        swoole_php_fatal_error(E_WARNING, "The host is empty.");
        RETURN_FALSE;
    }
    //读取swoole_client对应的内部扩展的对象信息,从前面分析可以知道,这里读取到的是null
    swClient *cli = (swClient *) swoole_get_object(getThis());
    if (cli)
    {
        swoole_php_fatal_error(E_WARNING, "connection to the server has already been established.");
        RETURN_FALSE;
    }
    //创建内部扩展的对象信息,也就是客户端socket对象信息
    cli = php_swoole_client_new(getThis(), host, host_len, port);
    if (cli == NULL)
    {
        RETURN_FALSE;
    }
    //重新设置对应关系
    swoole_set_object(getThis(), cli);

    if (cli->type == SW_SOCK_TCP || cli->type == SW_SOCK_TCP6)//如果要连接的通信类型为TCP
    {
        if (port <= 0 || port > SW_CLIENT_MAX_PORT)//判断端口有效性
        {
            swoole_php_fatal_error(E_WARNING, "The port is invalid.");
            RETURN_FALSE;
        }
        if (cli->async == 1)//如果是异步客户端
        {
            //for tcp: nonblock
            //for udp: have udp connect
            sock_flag = 1;
        }
    }

    if (cli->keep == 1 && cli->socket->active == 1)//如果是长连接,且连接是活跃的,更新swoole_client的重用信息,这里是扣减了1次。
    {
        zend_update_property_bool(swoole_client_class_entry_ptr, getThis(), SW_STRL("reuse")-1, 1 TSRMLS_CC);
        RETURN_TRUE;
    }
    else if (cli->socket->active == 1)//不是长连接,连接是活跃的,表示已经建立了连接
    {
        swoole_php_fatal_error(E_WARNING, "connection to the server has already been established.");
        RETURN_FALSE;
    }
    //读取swoole_client对象的setting信息
    zval *zset = sw_zend_read_property(swoole_client_class_entry_ptr, getThis(), ZEND_STRL("setting"), 1 TSRMLS_CC);
    if (zset && !ZVAL_IS_NULL(zset))
    {
        php_swoole_client_check_setting(cli, zset TSRMLS_CC);//检查setting信息设置,这里会将swoole_client的setting里面的信息更新到cli的相应属性上
    }

    //异步客户端
    if (cli->async)
    {
        //获取php侧回调函数信息,回调函数可以通过swoole_client对象的on方法设置
        client_callback *cb = (client_callback *) swoole_get_property(getThis(), 0);
        if (!cb)//回调函数信息为空,报错,中断流程
        {
            swoole_php_fatal_error(E_ERROR, "no event callback function.");
            RETURN_FALSE;
        }

        if (swSocket_is_stream(cli->type))//判断socket类型是否为TCP类型的
        {
            if (!cb->onConnect)//没有设置onConnect回调函数
            {
                swoole_php_fatal_error(E_ERROR, "no 'onConnect' callback function.");
                RETURN_FALSE;
            }
            if (!cb->onError)//没有设置onError回调函数
            {
                swoole_php_fatal_error(E_ERROR, "no 'onError' callback function.");
                RETURN_FALSE;
            }
            if (!cb->onClose)//没有设置onClose回调函数
            {
                swoole_php_fatal_error(E_ERROR, "no 'onClose' callback function.");
                RETURN_FALSE;
            }

            cli->onConnect = client_onConnect;//设置onConnect回调函数信息
            cli->onClose = client_onClose;//设置onClose回调函数信息
            cli->onError = client_onError;//设置onError回调函数信息
            cli->onReceive = client_onReceive;//设置onReceive回调函数信息
            cli->reactor_fdtype = PHP_SWOOLE_FD_STREAM_CLIENT;//客户端类型为流式协议,也就是TCP类型
            if (cb->onBufferFull)
            {
                cli->onBufferFull = client_onBufferFull;//设置onBufferFull回调函数信息
            }
            if (cb->onBufferEmpty)
            {
                cli->onBufferEmpty = client_onBufferEmpty;//设置onBufferEmpty回调函数信息
            }
        }
        else//如果是其他网络类型,这里只可能是UDP类型,也就是数据包协议
        {
            if (!cb || !cb->onReceive)//回调函数信息或者onReceive回调函数为空
            {
                swoole_php_fatal_error(E_ERROR, "no 'onReceive' callback function.");
                RETURN_FALSE;
            }
            if (cb->onConnect)
            {
                cli->onConnect = client_onConnect;//设置onConnect回调函数信息
            }
            if (cb->onClose)
            {
                cli->onClose = client_onClose;//设置onClose回调函数信息
            }
            cli->onReceive = client_onReceive;//设置onReceive回调函数信息
            cli->reactor_fdtype = PHP_SWOOLE_FD_DGRAM_CLIENT;//标记为数据包协议
        }

        zval *zobject = getThis();
        cli->object = zobject;//cli的属性值object设置为swoole_client对象
        sw_copy_to_stack(cli->object, cb->_object);//这里实现为空
        sw_zval_add_ref(&zobject);//增加引用计数信息
    }

    //执行正式的连接操作,这里基于创建的客户端类型不同,实际执行的connect也不同
    if (cli->connect(cli, host, port, timeout, sock_flag) < 0)//执行连接失败
    {
        if (errno == 0 )
        {
            if (SwooleG.error == SW_ERROR_DNSLOOKUP_RESOLVE_FAILED)
            {
                swoole_php_error(E_WARNING, "connect to server[%s:%d] failed. Error: %s[%d]", host, (int )port,
                        hstrerror(h_errno), h_errno);
            }
            //更新swoole_client的errCode属性
            zend_update_property_long(swoole_client_class_entry_ptr, getThis(), SW_STRL("errCode")-1, SwooleG.error TSRMLS_CC);
        }
        else
        {
            swoole_php_sys_error(E_WARNING, "connect to server[%s:%d] failed.", host, (int )port);
            //更新swoole_client的errCode属性
            zend_update_property_long(swoole_client_class_entry_ptr, getThis(), SW_STRL("errCode")-1, errno TSRMLS_CC);
        }
        RETURN_FALSE;
    }
    RETURN_TRUE;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值