其实也就是在实现行缓存读函数fgets
/* read just a single line or timeout */
int _readline(int fd, iobuffer *iobuf, void *buffer, size_t len, int timeout)
{ /*函数原理:从iobuf.buf中一个字节一个字节的将数据读取存放到buffer中去,直到遇见换行符"\n",或者长度达到了*/
char c = '\0', *out = buffer;
int i;
memset(buffer, 0, len);
for(i = 0; i < len && c != '\n'; i++) {
if(_read(fd, iobuf, &c, 1, timeout) <= 0) {
/* timeout or error occured */
return -1;
}
*out++ = c;
}
return i;
}
int _read(int fd, iobuffer *iobuf, void *buffer, size_t len, int timeout)
{
int copied = 0, rc, i;/*copied 表示已经读了多少字节*/
fd_set fds;
struct timeval tv;
memset(buffer, 0, len);
while((copied < len)) {
i = MIN(iobuf->level, len - copied);/*第一次 i=0,因为level初始化为0,又因为len为1且copied=0*/
memcpy(buffer + copied, iobuf->buffer + IO_BUFFER - iobuf->level, i);
iobuf->level -= i;
copied += i;
if(copied >= len) /*第二次读的时候copied=0,buffer还没有清空*/
return copied;
/* select will return in case of timeout or new data arrived
* 当客户端发有数据或者超时的时候,select函数就返回
*/
tv.tv_sec = timeout; /*每次进入都重新计时*/
tv.tv_usec = 0;
FD_ZERO(&fds);
FD_SET(fd, &fds);
if((rc = select(fd + 1, &fds, NULL, NULL, &tv)) <= 0) {
if(rc < 0)
exit(EXIT_FAILURE);
/* this must be a timeout,第二次读的时候,靠上面的返回不行了,只能依靠select超时返回 */
return copied;
}
init_iobuffer(iobuf);
/*
* there should be at least one byte, because select signalled it.
* But: It may happen (very seldomly), that the socket gets closed remotly between
* the select() and the following read. That is the reason for not relying
* on reading at least one byte.
*/
if((iobuf->level = read(fd, &iobuf->buffer, IO_BUFFER)) <= 0) {
/* an error occured */
return -1;
}
/* align data to the end of the buffer if less than IO_BUFFER bytes were read */
memmove(iobuf->buffer + (IO_BUFFER - iobuf->level), iobuf->buffer, iobuf->level);
}
return 0;
}