最近摸索着写了个简单的服务器,也阅读了一个小型webserver的源码,就是Tinyhttpd的源码。
发现,在从socket缓冲区读取一行方面,它的实现挺好玩,总结一下学习使用。
一般的话,从打开的fd中获得一行文本,调用的fgets();
例如:
int client;
FILE* pf = fdopen(client,"r");
char request[1024];
fgets(request,1024,pf);
他的实现是:
int get_line(int sock, char *buf, int size) { int i = 0; char c = '\0'; int n;
//读取直到换行,并且不管是'\r\n'结尾还是'\n'结尾,都统一成'\n'
while ((i < size - 1) && (c != '\n')) { n = recv(sock, &c, 1, 0);//读取一个字符 /* DEBUG printf("%02X\n", c); */ if (n > 0)//读到了这个字符 { if (c == '\r')//若是'\r'就继续读,因为可能是'\r''\n'换行的 { n = recv(sock, &c, 1, MSG_PEEK);//<span style="line-height: 22.1000003814697px; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;">MSG_PEEK参数类似于预读取,本次读取的值仍在缓冲区仍可重复被读</span> /* DEBUG printf("%02X\n", c); */ if ((n > 0) && (c == '\n'))//看看预读的数是否是'\n' recv(sock, &c, 1, 0);//如果是的话,就把'\n'彻底的从缓冲区中拿出来 else c = '\n';<span style="white-space:pre"> </span>//如果下个数不是'\n',就把'\r'也替换成'\n' } buf[i] = c; i++; } else c = '\n'; } buf[i] = '\0';//最后以'\0'结尾 return(i); }
具体解读过程已经在注释中。