我第三次尝试提出这个问题,也许这次我能够更好地解释我的问题。
我有一个多进程服务器,每个进程都在执行accept()(避免使用文件锁定的Thundering Herd问题,不用担心)。每个进程初始化一个线程池(切断主要管理其他的线程池)。当accept()成功时,文件描述符被传递给线程池,其中一个线程被pthread_cond_signal()唤醒。在此之后,进程返回文件锁定等待通过它,以便它可以在accept()上再次等待。同时,线程读取文件描述符并完成其工作:读取HTTP请求并在无限循环的读取服务中提供它(以获得HTTP持久连接)。只有在发生错误或超时到期时,循环才会被中断。
到目前为止一切顺利。但是在正确提供请求之后会发生一些事情:实际上,第一个请求被完全读取并提供,但是当线程重新启动循环并进入读取周期时,它仍然卡住,因为它只读取了几个字母,如" GE&# 34;或" GET",提出整个请求。如果我删除无限循环(对于持久连接),每个请求都由不同的线程提供,并且不会发生错误!!
这是阅读周期:
for (;;) {
ssize_t readn, writen;
size_t nleft;
char buff[BUFF_SIZE];
char *ptr = buff;
errno = 0;
nleft = BUFF_SIZE;
while(nleft > 0) {
//I will read as much as I can using the MSG_DONTWAIT flag making the call non-blocking
//that means that or the call will succed or it will be closed by the other side
if ((readn = recv(connsd, ptr, nleft, MSG_DONTWAIT)) < 0) {
//If the non-blocking recv fails, it could set errno with one of the following errorcode
if (errno == EAGAIN || errno == EWOULDBLOCK) {
//This check has been implemented due to an error that happened several times
//The buffer was empty even if a new data was sent.
//This check gives a sort of second chance to the recv.
if (strlen(buff) < 10) {
errno = 0; //It is important to reset the errno!!
continue;
//If other things occured then I will terminate the string and exit the cicle
} else {
break;
}
// If the conenction has been closed by the client
} else if (errno == EINTR) readn = 0;
// If other things occured I will simply shutdown the connection
else {
shutdown_sequence(connsd);
return EXIT_FAILURE;
}
// If I read nothing
} else if (readn == 0) break;
nleft -= readn;
ptr += readn;
}
buff[strlen(buff)-1] = '\0';
//request parsing...
//request serving...
}
感谢大家的耐心等待!
EDIT1:刚试过使用Wireshark来看看会发生什么。第一个请求被正确读取并提供,但随后我收到了#34; Continuation或非HTTP Traffic&#34;和[TCP窗口已满] ...我在Ubuntu 14.04中的虚拟机上尝试此服务器
EDIT2:我尝试了一个简单的循环:
while(nleft > 0) {
printf("Entering cylce and reading\n");
fflush(stdout);
if ((readn = recv(connsd, ptr, nleft, 0)) > 0) {
nleft -= readn;
ptr += readn;
printf("reading...\n");
fflush(stdout);
}
if (readn == 0) {
printf("connection closed or nothing more to read\n");
fflush(stdout);
break;
}
if (readn == -1) {
printf("error occurred\n");
fflush(stdout);
break;
}
}
在终端上我只阅读:
Entering cylce and reading
reading...
Entering cylce and reading
虽然Httperf(使用--num-calls = 2 --num-conns = 1调用)使用50%的CPU。当我按Ctrl + C终止它时,终端打印:
connection closed or nothing more to read
buff =
GET /1262662405106.jpg HTTP/1.1
User-Agent: httperf/0.9.0
Host: localhost
EDIT3:回应大卫:
while(nleft > 0) {
printf("I'm going on the read\n");
fflush(stdout);
if ((readn = recv(connsd, ptr, nleft, 0)) > 0) {
nleft -= readn;
ptr += readn;
if (*(ptr-2) == '\r' && *(ptr-1) == '\n') {
printf("It's an HTTP request\n");
fflush(stdout);
break;
} else continue;
} else if (errno == EINTR || readn == 0) {
break;
}
}
它完全识别出第一个HTTP请求,因为它打印了消息。但对于第二个它打印&#34;我正在阅读&#34;一旦。当我按Ctrl + C时,循环继续无限期地打印相同的消息。
EDIT4: 所以......问题出在HTTP响应中......标题错误,字符串分配错误。谢谢大卫先生!