swoole_process源码分析之write操作

版权声明:转载请注明来源 https://blog.csdn.net/u013702678/article/details/82928445

swoole_process提供的write方法用于向管道内写入数据,其使用的形式如下。

int swoole_process->write(string $data);
  • $data的长度在Linux系统下最大不超过8KMacOS/FreeBSD下最大不超过2K
  • 在子进程内调用write,父进程可以调用read接收此数据
  • 在父进程内调用write,子进程可以调用read接收此数据

下面我们分析下其使用流程。

static PHP_METHOD(swoole_process, write)
{
    char *data = NULL;
    zend_size_t data_len = 0;
    
    //解析输入参数,这里输入参数只有data字段,表示要发送的数据信息
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data, &data_len) == FAILURE)
    {
        RETURN_FALSE;
    }

    if (data_len < 1)//发送数据的长度异常
    {
        swoole_php_fatal_error(E_WARNING, "the data to send is empty.");
        RETURN_FALSE;
    }

    swWorker *process = swoole_get_object(getThis());//获取swoole内部封装对象
    if (process->pipe == 0)
    {
        swoole_php_fatal_error(E_WARNING, "no pipe, can not write into pipe.");
        RETURN_FALSE;
    }

    int ret;

    //异步写,进程内使用了swoole_event_add等,这时将会通过多路复用监听去完成写操作
    if (SwooleG.main_reactor)
    {
        swConnection *_socket = swReactor_get(SwooleG.main_reactor, process->pipe);//从多路复用管理器中获取连接信息
        if (_socket && _socket->nonblock)//想要的管道可以写入,且有异步属性
        {
            ret = SwooleG.main_reactor->write(SwooleG.main_reactor, process->pipe, data, (size_t) data_len);//通过多路复用写入
        }
        else//其他
        {
            goto _blocking_read;//goto跳转到阻塞式写入
        }
    }
    else//同步写,也就是阻塞式的写入,等待写入完成
    {
        _blocking_read: ret = swSocket_write_blocking(process->pipe, data, data_len);
    }

    if (ret < 0)
    {
        swoole_php_error(E_WARNING, "write() failed. Error: %s[%d]", strerror(errno), errno);
        RETURN_FALSE;
    }
    ZVAL_LONG(return_value, ret);
}
int swSocket_write_blocking(int __fd, void *__data, int __len)
{
    int n = 0;
    int written = 0;

    while (written < __len)
    {
        n = write(__fd, __data + written, __len - written);
        if (n < 0)
        {
            if (errno == EINTR)
            {
                continue;
            }
#ifdef HAVE_KQUEUE
            else if (errno == EAGAIN || errno == ENOBUFS)
#else
            else if (errno == EAGAIN)
#endif
            {
                swSocket_wait(__fd, SW_WORKER_WAIT_TIMEOUT, SW_EVENT_WRITE);
                continue;
            }
            else
            {
                swSysError("write %d bytes failed.", __len);
                return SW_ERR;
            }
        }
        written += n;
    }

    return written;
}

猜你喜欢

转载自blog.csdn.net/u013702678/article/details/82928445