2011-12-16 167 views
2

所以我編寫了一個多線程的Web服務器,這裏是程序的一個功能。此功能將輸出文件描述符(fd),內容類型,指向要提供的數據的指針(*buf)和數據大小(numbytes)。它始終卡在5775字節!我試過使用write()而不是send(),但無濟於事!我試圖一次發送整個buf,甚至試圖將它轉換成塊,但是wget顯示它在5775字節處得到!下面是代碼:無法通過TCP連接發送整個文件! (UNIX C)

int return_result(int fd, char *content_type, char *buf, int numbytes) 
{ 
    char out_buf[BUF_SIZE], numb[6]; 
    int buf_len, total = 0, buf_size; 
    long int i = 0; 
    sprintf(numb, "%d", numbytes); 
    strcpy(out_buf, "HTTP/1.1 200 OK \nContent-Type: "); 
    strcat(out_buf, content_type); 
    strcat(out_buf, "\nContent-Length: "); 
    strcat(out_buf, numb); 
    strcat(out_buf, "\nConnection: Close\n \n"); 
    printf("\nSending HTTP Header\n %d bytes sent!", 
      send(fd, out_buf, strlen(out_buf), 0)); 
    char *start = NULL, *str = NULL, *temp = NULL; 
    start = buf; 
    printf("\n Start Pointer Val = %ld", &start); 
    while (start != NULL) { 
     printf("\n While Loop"); 
     if (i + 2048 * sizeof(char) < numbytes) { 
      printf("\n If 1"); 
      str = (char *)malloc(sizeof(char) * 2048); 
      memcpy(str, start, sizeof(char) * 2048); 
      i = i + 2048 * sizeof(char); 
      buf_size = send(fd, str, 2048, 0); 
      free(str); 
      printf("\n Sent %d bytes total : %d", buf_size, total = 
        total + buf_size); 

      temp = start + sizeof(char) * 2048; 
      start = temp; 

     } else { 

      i = numbytes - i * sizeof(char); 
      if (i > 0) { 
       printf("\n If 2"); 
       printf("\n Value of i %d", i); 
       str = (char *)malloc(sizeof(char) * i); 
       memcpy(str, start, sizeof(char) * i); 
       printf("Total bytes finally sent:%d", total = 
         total + send(fd, str, i, 0)); 
       if (total == numbytes) { 
        printf("\nTransfer Complete!"); 
       } 
       free(str); 

      } 
      start = NULL; 
     } 
    } 
    printf("out of loop!"); 
    return 0; 
} 
+0

你實際上得到的「總字節數最後送:...」信息匹配,你期待什麼?如果是這樣,它可能是一個緩衝/沖洗問題。 – 2011-12-16 01:13:24

+0

是的,事實上我發送()從服務器端的所有字節,但wget只收到5775! – Zombie 2011-12-16 01:16:18

回答

1

嘗試是這樣的(printf()報表爲清楚起見省略):

int send_buf(in fd, void *buf, int numbytes) 
{ 
    char *start = (char*) buf; 
    while (numbytes > 0) 
    { 
     int sent = send(fd, start, numbytes, 0); 
     if (sent <= 0) 
     { 
      if ((sent == -1) && (errno == EAGAIN)) 
      { 
       fd_set wfds; 
       FD_ZERO(&wfds); 
       FD_SET(fd, &wfds); 
       if (select(fd + 1, NULL, &wfds, NULL, NULL) == 1) 
        continue; 
      } 
      return -1; 
     } 

     start += sent; 
     numbytes -= sent; 
    } 

    return 0; 
} 

int return_result(int fd, char *content_type, void *buf, int numbytes) 
{ 
    char out_buf[BUF_SIZE], 

    int len = sprintf(out_buf, 
     "HTTP/1.1 200 OK\r\n" 
     "Content-Type: %s\r\n" 
     "Content-Length: %d\r\n" 
     "Connection: Close\r\n" 
     "\r\n", 
     content_type, 
     numb); 

    if (send_buf(fd, out_buf, len) != 0) 
     return -1; 

    if (send_buf(fd, buf, numbytes) != 0) 
     return -1; 

    return 0; 
} 
2

我想建議從Advanced Programming in the Unix Environment, 2nd edition具有以下writen()函數替換代碼:

ssize_t    /* Write "n" bytes to a descriptor */ 
writen(int fd, const void *ptr, size_t n) 
{ 
     size_t   nleft; 
     ssize_t   nwritten; 

     nleft = n; 
     while (nleft > 0) { 
       if ((nwritten = write(fd, ptr, nleft)) < 0) { 
         if (nleft == n) 
           return(-1); /* error, return -1 */ 
         else 
           break;  /* error, return amount written so far */ 
       } else if (nwritten == 0) { 
         break; 
       } 
       nleft -= nwritten; 
       ptr += nwritten; 
     } 
     return(n - nleft);  /* return >= 0 */ 
} 

該代碼已經調試和已知的工作,並且還允許write(2)到在工作正常的情況下,一次寫入PIPE_BUF字節以獲得更好的速度。

send(2)應該塊,如果它不能發送你請求的所有數據,但。我認爲更有意思的是在沒有任何周圍努力將事情分解成塊的情況下調試版本的簡單send(2)。比這兩個write(2)send(2)

更好的將是sendfile(2) - 打開文件,描述符和插座傳遞給sendfile(2),並讓內核來處理這一切對你來說,使用零拷貝機制,如果可能的話。

最後一點:HTTP uses CRLF,不是普通的回車。每個\n應替換爲\r\n

+0

非常感謝您的意見!我添加了你的代碼,但wget仍然卡在5775字節!我轉入不同的機器,結果我到處都遇到同樣的問題!有什麼想法嗎? – Zombie 2011-12-16 01:29:14