typedefstructconn conn; structconn { //.... /* data for the mwrite state */ //iov主要存储iov的数据结构 //iov数据结构会在conn_new中初始化,初始化的时候,系统会分配400个iovec的结构,最高水位600个 structiovec *iov; //iov的长度 int iovsize; /* number of elements allocated in iov[] */ //iovused 这个主要记录iov使用了多少 int iovused; /* number of elements used in iov[] */ //msglist主要存储msghdr的列表数据结构 //msglist数据结构在conn_new中初始化的时候,系统会分配10个结构 structmsghdr *msglist; //msglist的长度,初始化为10个,最高水位100,不够用的时候会realloc,每次扩容都会扩容一倍 int msgsize; /* number of elements allocated in msglist[] */ //msglist已经使用的长度 int msgused; /* number of elements used in msglist[] */ //这个参数主要帮助记录那些msglist已经发送过了,哪些没有发送过。 int msgcurr; /* element in msglist[] being transmitted now */ int msgbytes; /* number of bytes in current msg */ }
staticintadd_iov(conn *c, constvoid *buf, int len){ structmsghdr *m; int leftover; bool limit_to_mtu; assert(c != NULL); do { //消息数组 msglist 存储msghdr结构 //这边是获取最新的msghdr数据结构指针 m = &c->msglist[c->msgused - 1]; /* * Limit UDP packets, and the first payloads of TCP replies, to * UDP_MAX_PAYLOAD_SIZE bytes. */ limit_to_mtu = IS_UDP(c->transport) || (1 == c->msgused); /* We may need to start a new msghdr if this one is full. */ //如果msghdr结构中的iov满了,则需要使用更新的msghdr数据结构 if (m->msg_iovlen == IOV_MAX || (limit_to_mtu && c->msgbytes >= UDP_MAX_PAYLOAD_SIZE)) { //添加msghdr,这个方法中回去判断初始化的时候10个msghdr结构是否够用,不够用的话会扩容 add_msghdr(c); //指向下一个新的msghdr数据结构 m = &c->msglist[c->msgused - 1]; } //确认IOV的空间大小,初始化默认是400个,水位600 //如果IOV也不够用了,就会去扩容 if (ensure_iov_space(c) != 0) return-1; /* If the fragment is too big to fit in the datagram, split it up */ if (limit_to_mtu && len + c->msgbytes > UDP_MAX_PAYLOAD_SIZE) { leftover = len + c->msgbytes - UDP_MAX_PAYLOAD_SIZE; len -= leftover; } else { leftover = 0; } m = &c->msglist[c->msgused - 1]; //m->msg_iov参数指向c->iov这个结构。 //具体m->msg_iov如何指向到c->iov这个结构的,需要看一下add_msghdr这个方法 //向IOV中填充BUF m->msg_iov[m->msg_iovlen].iov_base = (void *) buf; //buf的长度 m->msg_iov[m->msg_iovlen].iov_len = len; //填充长度 c->msgbytes += len; c->iovused++; m->msg_iovlen++; //msg_iovlen + 1 buf = ((char *) buf) + len; len = leftover; } while (leftover > 0); return0; }
//这个方法主要向客户端写数据 //如果数据没有发送完,则会一直循环conn_mwrite这个状态,直到数据发送完成为止 staticenum transmit_result transmit(conn *c){ assert(c != NULL); //每次发送之前,都会来校验前一次的数据是否发送完了 //如果前一次的msghdr结构体内的数据已经发送完了,则c->msgcurr指针就会往后移动一位, //移动到下一个等待发送的msghdr结构体指针上 //c->msgcurr初始值为:0 if (c->msgcurr < c->msgused && c->msglist[c->msgcurr].msg_iovlen == 0) { /* Finished writing the current msg; advance to the next. */ c->msgcurr++; } //如果c->msgcurr(已发送)小于c->msgused(已使用),则就可以知道还没发送完,则需要继续发送 //如果c->msgcurr(已发送)等于c->msgused(已使用),则说明已经发送完了,返回TRANSMIT_COMPLETE状态 if (c->msgcurr < c->msgused) { ssize_t res; //从c->msglist取出一个待发送的msghdr结构 structmsghdr *m = &c->msglist[c->msgcurr]; //向客户端发送数据 res = sendmsg(c->sfd, m, 0); //发送成功的情况 if (res > 0) { pthread_mutex_lock(&c->thread->stats.mutex); c->thread->stats.bytes_written += res; pthread_mutex_unlock(&c->thread->stats.mutex); /* We've written some of the data. Remove the completed iovec entries from the list of pending writes. */ //这边会检查发送了多少 while (m->msg_iovlen > 0 && res >= m->msg_iov->iov_len) { res -= m->msg_iov->iov_len; m->msg_iovlen--; m->msg_iov++; } /* Might have written just part of the last iovec entry; adjust it so the next write will do the rest. */ if (res > 0) { m->msg_iov->iov_base = (caddr_t) m->msg_iov->iov_base + res; m->msg_iov->iov_len -= res; } return TRANSMIT_INCOMPLETE; } //发送失败的情况 if (res == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) { if (!update_event(c, EV_WRITE | EV_PERSIST)) { if (settings.verbose > 0) fprintf(stderr, "Couldn't update event\n"); conn_set_state(c, conn_closing); return TRANSMIT_HARD_ERROR; } return TRANSMIT_SOFT_ERROR; } /* if res == 0 or res == -1 and error is not EAGAIN or EWOULDBLOCK, we have a real error, on which we close the connection */ if (settings.verbose > 0) perror("Failed to write, and not due to blocking"); if (IS_UDP(c->transport)) conn_set_state(c, conn_read); else conn_set_state(c, conn_closing); return TRANSMIT_HARD_ERROR; } else { return TRANSMIT_COMPLETE; } }