多进程和多线程C服务器上的持久连接

时间:2015-08-24 11:10:12

标签: c multithreading tcp multiprocessing persistent-connection

我第三次尝试提出这个问题,也许这次我能够更好地解释我的问题。

我有一个多进程服务器,每个进程都在执行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响应中......标题错误,字符串分配错误。谢谢大卫先生!

0 个答案:

没有答案