如何建设一个工业品采购网站百度云网盘资源
前面我们分析了客户端swoole_client的connect过程,从里面代码可以看出,swClient在connect过程中设置了各种其他动作的回调函数,这里我们接着分析余下的流程,同时把回调函数实现也关注下。
//swoole_client的send函数实现
static PHP_METHOD(swoole_client, send)
{char *data;zend_size_t data_len;zend_long flags = 0;//解析输入参数信息,这里解析出了data,data长度信息data_len,flag信息,解析也分新的扩展方式和旧的扩展方式
#ifdef FAST_ZPPZEND_PARSE_PARAMETERS_START(1, 2)Z_PARAM_STRING(data, data_len)Z_PARAM_OPTIONALZ_PARAM_LONG(flags)ZEND_PARSE_PARAMETERS_END();
#elseif (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &data, &data_len, &flags) == FAILURE){return;}
#endifif (data_len <= 0) //数据长度小于等于0{swoole_php_fatal_error(E_WARNING, "data to send is empty.");RETURN_FALSE;}swClient *cli = client_get_ptr(getThis() TSRMLS_CC);//基于当前php对象swoole_client获取到swoole内部的封装对象信息swClientif (!cli)//对象信息为空{RETURN_FALSE;}//clear errnoSwooleG.error = 0;int ret = cli->send(cli, data, data_len, flags);//调用swClient的send函数发送数据if (ret < 0) //发送失败{swoole_php_sys_error(E_WARNING, "failed to send(%d) %zd bytes.", cli->socket->fd, data_len);zend_update_property_long(swoole_client_class_entry_ptr, getThis(), SW_STRL("errCode")-1, SwooleG.error TSRMLS_CC);//更新swoole_client的errCode属性信息RETVAL_FALSE;}else{RETURN_LONG(ret);}
}
如开篇所说,我们在connect过程中设置了swClient的send回调函数,我们继续分析这个回调函数的实现,客户端在创建时,基于同步和异步区别,在执行send时,流程是不同的,不同点在于,如果是同步的,则多次发送数据直到发送数据完毕,如果是异步的,通过多路复用的方式处理,这里其实是模拟了异步,不是真正的异步,我们重点看看同步的,异步的代码也贴出来,不做实际分析。
cli->connect = swClient_tcp_connect_sync;//同步回调函数设置
cli->send = swClient_tcp_send_async;//异步回调函数设置
//标准的tcp数据发送,多次发送直到数据发送完成,中间需要判断send返回值做处理
static int swClient_tcp_send_sync(swClient *cli, char *data, int length, int flags)
{int written = 0;int n;assert(length > 0);assert(data != NULL);while (written < length){n = swConnection_send(cli->socket, data, length - written, flags);if (n < 0){if (errno == EINTR){continue;}else if (errno == EAGAIN){swSocket_wait(cli->socket->fd, 1000, SW_EVENT_WRITE);continue;}else{SwooleG.error = errno;return SW_ERR;}}written += n;data += n;}return written;
}
static sw_inline int swConnection_send(swConnection *conn, void *__buf, size_t __n, int __flags)
{int retval;
#ifdef SW_USE_OPENSSLif (conn->ssl){retval = swSSL_send(conn, __buf, __n);}else{retval = send(conn->fd, __buf, __n, __flags);}
#elseretval = send(conn->fd, __buf, __n, __flags);//调用linux函数send做发送动作
#endif#ifdef SW_DEBUGif (retval > 0){conn->total_send_bytes += retval;//统计实际发送的字节数}
#endifreturn retval;
}
异步发送过程代码如下,不做解析,这里重点是调用了reactor的接口去发送,而reactor在做处理时,会用多路复用。
static int swClient_tcp_send_async(swClient *cli, char *data, int length, int flags)
{int n = length;if (cli->reactor->write(cli->reactor, cli->socket->fd, data, length) < 0){if (SwooleG.error == SW_ERROR_OUTPUT_BUFFER_OVERFLOW){n = -1;cli->socket->high_watermark = 1;}else{return SW_ERR;}}if (cli->onBufferFull && cli->socket->out_buffer && cli->socket->high_watermark == 0&& cli->socket->out_buffer->length >= cli->buffer_high_watermark){cli->socket->high_watermark = 1;cli->onBufferFull(cli);}return n;
}