2011-12-16 100 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