int swClient_tcp_send_async(swClient *cli, char *data, int length) { if (cli->out_buffer == NULL) { cli->out_buffer = swBuffer_new(SW_BUFFER_SIZE); if (cli->out_buffer == NULL) { return SW_ERR; } } if (swBuffer_empty(cli->out_buffer)) { SwooleG.main_reactor->set(SwooleG.main_reactor, cli->sock, cli->reactor_fdtype | SW_EVENT_READ | SW_EVENT_WRITE); } /** * append data to buffer */ if (swBuffer_append(cli->out_buffer, data, length) < 0) { return SW_ERR; } return SW_OK; }
int swClient_tcp_send_async(swClient *cli, char *data, int length) { if (cli->out_buffer == NULL) { cli->out_buffer = swBuffer_new(SW_BUFFER_SIZE); if (cli->out_buffer == NULL) { return SW_ERR; } } swSendData _send; _send.info.fd = cli->sock; _send.info.len = length; _send.data = data; if (swBuffer_empty(cli->out_buffer)) { SwooleG.main_reactor->set(SwooleG.main_reactor, cli->sock, cli->reactor_fdtype | SW_EVENT_READ | SW_EVENT_WRITE); } if (swBuffer_in(cli->out_buffer, &_send) < 0) { return SW_ERR; } return SW_OK; }
int swFactory_end(swFactory *factory, int fd) { swServer *serv = factory->ptr; swSendData _send; swDataHead info; bzero(&_send, sizeof(_send)); _send.info.fd = fd; _send.info.len = 0; _send.info.type = SW_EVENT_CLOSE; swConnection *conn = swWorker_get_connection(serv, fd); if (conn == NULL || conn->active == 0) { //swWarn("can not close. Connection[%d] not found.", _send.info.fd); return SW_ERR; } else if (conn->close_force) { goto do_close; } else if (conn->closing) { swWarn("The connection[%d] is closing.", fd); return SW_ERR; } else if (conn->closed) { return SW_ERR; } else { do_close: conn->closing = 1; if (serv->onClose != NULL) { info.fd = fd; info.from_id = conn->from_id; info.from_fd = conn->from_fd; serv->onClose(serv, &info); } conn->closing = 0; conn->closed = 1; conn->close_errno = 0; if (swBuffer_empty(conn->out_buffer)) { swReactor *reactor = &serv->reactor_threads[SwooleTG.id].reactor; return swReactorThread_close(reactor, conn->fd); } else { swBuffer_trunk *trunk = swBuffer_new_trunk(conn->out_buffer, SW_CHUNK_CLOSE, 0); trunk->store.data.val1 = _send.info.type; return SW_OK; } } }
static int swClient_tcp_sendfile_async(swClient *cli, char *filename) { if (swBuffer_empty(cli->connection.out_buffer)) { SwooleG.main_reactor->set(SwooleG.main_reactor, cli->connection.fd, cli->reactor_fdtype | SW_EVENT_READ | SW_EVENT_WRITE); } if (swConnection_sendfile(&cli->connection, filename) < 0) { SwooleG.error = errno; return SW_ERR; } return SW_OK; }
/** * worker: send to client */ static int swFactoryProcess_finish(swFactory *factory, swSendData *resp) { int ret, sendn; swServer *serv = factory->ptr; int session_id = resp->info.fd; swConnection *conn; if (resp->info.type != SW_EVENT_CLOSE) { conn = swServer_connection_verify(serv, session_id); } else { conn = swServer_connection_verify_no_ssl(serv, session_id); } if (!conn) { swoole_error_log(SW_LOG_NOTICE, SW_ERROR_SESSION_NOT_EXIST, "connection[fd=%d] does not exists.", session_id); return SW_ERR; } else if ((conn->closed || conn->removed) && resp->info.type != SW_EVENT_CLOSE) { int _len = resp->length > 0 ? resp->length : resp->info.len; swoole_error_log(SW_LOG_NOTICE, SW_ERROR_SESSION_CLOSED, "send %d byte failed, because connection[fd=%d] is closed.", _len, session_id); return SW_ERR; } else if (conn->overflow) { swoole_error_log(SW_LOG_WARNING, SW_ERROR_OUTPUT_BUFFER_OVERFLOW, "send failed, connection[fd=%d] output buffer has been overflowed.", session_id); return SW_ERR; } swEventData ev_data; ev_data.info.fd = session_id; ev_data.info.type = resp->info.type; swWorker *worker = swServer_get_worker(serv, SwooleWG.id); /** * Big response, use shared memory */ if (resp->length > 0) { if (worker == NULL || worker->send_shm == NULL) { goto pack_data; } //worker process if (SwooleG.main_reactor) { int _pipe_fd = swWorker_get_send_pipe(serv, session_id, conn->from_id); swConnection *_pipe_socket = swReactor_get(SwooleG.main_reactor, _pipe_fd); //cannot use send_shm if (!swBuffer_empty(_pipe_socket->out_buffer)) { pack_data: if (swTaskWorker_large_pack(&ev_data, resp->data, resp->length) < 0) { return SW_ERR; } ev_data.info.from_fd = SW_RESPONSE_TMPFILE; goto send_to_reactor_thread; } } swPackage_response response; response.length = resp->length; response.worker_id = SwooleWG.id; ev_data.info.from_fd = SW_RESPONSE_SHM; ev_data.info.len = sizeof(response); memcpy(ev_data.data, &response, sizeof(response)); swTrace("[Worker] big response, length=%d|worker_id=%d", response.length, response.worker_id); worker->lock.lock(&worker->lock); memcpy(worker->send_shm, resp->data, resp->length); } else { //copy data memcpy(ev_data.data, resp->data, resp->info.len); ev_data.info.len = resp->info.len; ev_data.info.from_fd = SW_RESPONSE_SMALL; } send_to_reactor_thread: ev_data.info.from_id = conn->from_id; sendn = ev_data.info.len + sizeof(resp->info); swTrace("[Worker] send: sendn=%d|type=%d|content=%s", sendn, resp->info.type, resp->data); ret = swWorker_send2reactor(&ev_data, sendn, session_id); if (ret < 0) { swWarn("sendto to reactor failed. Error: %s [%d]", strerror(errno), errno); } return ret; }
/** * send to client or append to out_buffer */ int swReactorThread_send(swEventData *resp) { int buf_size, copy_n; swServer *serv = SwooleG.serv; swSendData send_data; swEvent closeFd; swBuffer_trunk *trunk; swTask_sendfile *task; swConnection *conn = swServer_get_connection(serv, resp->info.fd); swReactor *reactor = &(serv->reactor_threads[conn->from_id].reactor); //recv length=0, will close connection if (resp->info.len == 0) { #ifdef SW_REACTOR_DIRECT_SEND close_fd: #endif { closeFd.fd = resp->info.fd; closeFd.from_id = resp->info.from_id; closeFd.type = SW_EVENT_CLOSE; //printf("closeFd.fd=%d|from_id=%d\n", closeFd.fd, closeFd.from_id); swReactorThread_onClose(reactor, &closeFd); } return SW_OK; } //sendfile to client else if(resp->info.type == SW_EVENT_SENDFILE) { trunk = swConnection_get_out_buffer(conn, SW_TRUNK_SENDFILE); if (trunk == NULL) { swWarn("get out_buffer trunk failed."); return SW_ERR; } task = sw_malloc(sizeof(swTask_sendfile)); if (task == NULL) { swWarn("malloc for swTask_sendfile failed."); //TODO: 回收这里的内存 return SW_ERR; } bzero(task, sizeof(swTask_sendfile)); int file_fd = open(resp->data, O_RDONLY); if (file_fd < 0) { swWarn("open file[%s] failed. Error: %s[%d]", task->filename, strerror(errno), errno); return SW_ERR; } struct stat file_stat; if (fstat(file_fd, &file_stat) < 0) { swWarn("swoole_async_readfile: fstat failed. Error: %s[%d]", strerror(errno), errno); return SW_ERR; } task->filesize = file_stat.st_size; task->fd = file_fd; trunk->data = (void *)task; reactor->set(reactor, resp->info.fd, SW_EVENT_TCP | SW_EVENT_WRITE | SW_EVENT_READ); } //send data else { send_data.data = resp->data; send_data.info.len = resp->info.len; send_data.info.from_id = resp->info.from_id; send_data.info.fd = resp->info.fd; #ifdef SW_REACTOR_DIRECT_SEND if(!swBuffer_empty(conn->out_buffer)) { trunk = swBuffer_get_trunk(conn->out_buffer); #else { trunk = swConnection_get_out_buffer(conn, SW_TRUNK_DATA); #endif buf_size = conn->out_buffer->trunk_size - trunk->length; #ifdef SW_REACTOR_DIRECT_SEND append_out_buffer: #else //listen EPOLLOUT event reactor->set(reactor, resp->info.fd, SW_EVENT_TCP | SW_EVENT_WRITE | SW_EVENT_READ); #endif do { copy_n = (buf_size >= send_data.info.len) ? send_data.info.len : buf_size; memcpy(trunk->data, send_data.data, copy_n); send_data.data += copy_n; send_data.info.len -= copy_n; trunk->length += copy_n; buf_size += copy_n; //trunk is full, create new trunk if (trunk->length == conn->out_buffer->trunk_size) { //trunk no enough space, creating a new trunk trunk = swBuffer_new_trunk(conn->out_buffer, SW_TRUNK_DATA); if (trunk == NULL) { swWarn("append to out_buffer failed."); return SW_ERR; } buf_size = conn->out_buffer->trunk_size; } } while(send_data.info.len > 0); } #ifdef SW_REACTOR_DIRECT_SEND else { //try send int ret = swWrite(send_data.info.fd, send_data.data, send_data.info.len); if (ret < 0) { //连接已被关闭 if (errno == ECONNRESET || errno == EBADF) { goto close_fd; } swWarn("factory->onFinish failed.fd=%d|from_id=%d. Error: %s[%d]", resp->info.fd, resp->info.from_id, strerror(errno), errno); } //Did not finish, add to writable event callback else if(ret < resp->info.len) { trunk = swConnection_get_out_buffer(conn, SW_TRUNK_DATA); send_data.data += ret; send_data.info.len -= ret; buf_size = conn->out_buffer->trunk_size; goto append_out_buffer; } //printf("[writer]pop.fd=%d|from_id=%d|data=%s\n", resp->info.fd, resp->info.from_id, resp->data); } #endif }