SWINLINE swBuffer_trunk* swConnection_get_out_buffer(swConnection *conn, uint32_t type) { swBuffer_trunk *trunk; if (conn->out_buffer == NULL) { conn->out_buffer = swBuffer_new(SW_BUFFER_SIZE); if (conn->out_buffer == NULL) { return NULL; } } if (type == SW_TRUNK_SENDFILE) { trunk = swBuffer_new_trunk(conn->out_buffer, SW_TRUNK_SENDFILE, 0); } else { trunk = swBuffer_get_trunk(conn->out_buffer); if (trunk == NULL) { trunk = swBuffer_new_trunk(conn->out_buffer, SW_TRUNK_DATA, conn->out_buffer->trunk_size); } } return trunk; }
int swConnection_send_in_buffer(swConnection *conn) { int ret; #ifdef SW_DEBUG int i; #endif swFactory *factory = SwooleG.factory; swEventData _send; swBuffer *buffer = conn->in_buffer; swBuffer_trunk *trunk = swBuffer_get_trunk(buffer); _send.info.fd = conn->fd; _send.info.type = (buffer->trunk_num == 1) ? SW_EVENT_TCP : SW_EVENT_PACKAGE_START; _send.info.from_id = conn->from_id; while (trunk != NULL) { _send.info.len = trunk->length; memcpy(_send.data, trunk->data, _send.info.len); ret = factory->dispatch(factory, &_send); //TODO: 处理数据失败,数据将丢失 if (ret < 0) { swWarn("factory->dispatch failed."); } swBuffer_pop_trunk(buffer, trunk); trunk = swBuffer_get_trunk(buffer); swTrace("send2worker[i=%d][trunk_num=%d][type=%d]\n", i++, buffer->trunk_num, _send.info.type); if (_send.info.type == SW_EVENT_PACKAGE_START) { _send.info.type = SW_EVENT_PACKAGE_TRUNK; } //package end if (trunk == NULL || trunk->next == NULL) { _send.info.type = SW_EVENT_PACKAGE_END; } } return SW_OK; }
/** * send buffer to client */ int swConnection_buffer_send(swConnection *conn) { int ret, sendn; swBuffer *buffer = conn->out_buffer; swBuffer_trunk *trunk = swBuffer_get_trunk(buffer); sendn = trunk->length - trunk->offset; if (sendn == 0) { swBuffer_pop_trunk(buffer, trunk); return SW_CONTINUE; } ret = swConnection_send(conn, trunk->store.ptr + trunk->offset, sendn, 0); //printf("BufferOut: reactor=%d|sendn=%d|ret=%d|trunk->offset=%d|trunk_len=%d\n", reactor->id, sendn, ret, trunk->offset, trunk->length); if (ret < 0) { switch (swConnection_error(conn->fd, errno)) { case SW_ERROR: swWarn("send to fd[%d] failed. Error: %s[%d]", conn->fd, strerror(errno), errno); return SW_OK; case SW_CLOSE: return SW_CLOSE; case SW_WAIT: return SW_WAIT; default: return SW_CONTINUE; } } //trunk full send else if(ret == sendn || sendn == 0) { swBuffer_pop_trunk(buffer, trunk); } else { trunk->offset += ret; } return SW_CONTINUE; }
/** * send buffer to client */ int swBuffer_send(swBuffer *buffer, int fd) { int ret, sendn; swBuffer_trunk *trunk = swBuffer_get_trunk(buffer); sendn = trunk->length - trunk->offset; if (sendn == 0) { swBuffer_pop_trunk(buffer, trunk); return SW_CONTINUE; } ret = send(fd, trunk->data + trunk->offset, sendn, 0); //printf("BufferOut: reactor=%d|sendn=%d|ret=%d|trunk->offset=%d|trunk_len=%d\n", reactor->id, sendn, ret, trunk->offset, trunk->length); if (ret < 0) { if (swConnection_error(fd, errno) < 0) { return SW_CLOSE; } else if(errno == EAGAIN) { return SW_WAIT; } else { swWarn("send to fd[%d] failed. Error: %s[%d]", fd, strerror(errno), errno); return SW_CONTINUE; } } //trunk full send else if(ret == sendn || sendn == 0) { swBuffer_pop_trunk(buffer, trunk); } else { trunk->offset += ret; } return SW_CONTINUE; }
int swConnection_send_in_buffer(swConnection *conn) { swFactory *factory = SwooleG.factory; swEventData _send; _send.info.fd = conn->fd; _send.info.from_id = conn->from_id; #ifdef SW_USE_RINGBUFFER swServer *serv = SwooleG.serv; swMemoryPool *pool = serv->reactor_threads[conn->from_id].pool; swPackage package; package.length = 0; while (1) { package.data = pool->alloc(pool, buffer->length); if (package.data == NULL) { swYield(); swWarn("reactor memory pool full."); continue; } break; } _send.info.type = SW_EVENT_PACKAGE; while (trunk != NULL) { _send.info.len = trunk->length; memcpy(package.data + package.length , trunk->data, trunk->length); package.length += trunk->length; swBuffer_pop_trunk(buffer, trunk); trunk = swBuffer_get_trunk(buffer); } _send.info.len = sizeof(package); memcpy(_send.data, &package, sizeof(package)); //swWarn("[ReactorThread] copy_n=%d", package.length); return factory->dispatch(factory, &_send); #else swBuffer *buffer = conn->in_buffer; swBuffer_trunk *trunk = swBuffer_get_trunk(buffer); int ret; _send.info.type = SW_EVENT_PACKAGE_START; /** * lock target */ SwooleTG.factory_lock_target = 1; while (trunk != NULL) { _send.info.len = trunk->length; memcpy(_send.data, trunk->store.ptr, _send.info.len); //package end if (trunk->next == NULL) { _send.info.type = SW_EVENT_PACKAGE_END; } ret = factory->dispatch(factory, &_send); //TODO: 处理数据失败,数据将丢失 if (ret < 0) { swWarn("factory->dispatch failed."); } swBuffer_pop_trunk(buffer, trunk); trunk = swBuffer_get_trunk(buffer); swTrace("send2worker[trunk_num=%d][type=%d]\n", buffer->trunk_num, _send.info.type); } /** * unlock */ SwooleTG.factory_target_worker = -1; SwooleTG.factory_lock_target = 0; #endif return SW_OK; }
/** * 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 }