2011-06-07 100 views
0

我修改了beej的網絡示例指南(如下所示)以將html響應傳遞迴瀏覽器。我得到「連接被重置」每隔幾次刷新,似乎無法弄清楚爲什麼?就好像它在發送html響應之前關閉連接一樣。C服務器 - 「連接已重置」

任何想法或建議調試?

編輯:它有時傳遞正確的數據到瀏覽器。

下面是代碼:

/* 
** server.c -- a stream socket server demo 
*/ 

#include <iostream> 
#include <string> 
#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <errno.h> 
#include <string.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <netdb.h> 
#include <arpa/inet.h> 
#include <sys/wait.h> 
#include <signal.h> 

#define PORT "8080" // the port users will be connecting to 

#define BACKLOG 10000 // how many pending connections queue will hold 

using namespace std; 

void sigchld_handler(int s) 
{ 
    while(waitpid(-1, NULL, WNOHANG) > 0); 
} 

// get sockaddr, IPv4 or IPv6: 
void *get_in_addr(struct sockaddr *sa) 
{ 
    if (sa->sa_family == AF_INET) { 
     return &(((struct sockaddr_in*)sa)->sin_addr); 
    } 

    return &(((struct sockaddr_in6*)sa)->sin6_addr); 
} 

int main(void) 
{ 
    int sockfd, new_fd; // listen on sock_fd, new connection on new_fd 
    struct addrinfo hints, *servinfo, *p; 
    struct sockaddr_storage their_addr; // connector's address information 
    socklen_t sin_size; 
    struct sigaction sa; 
    int yes=1; 
    char s[INET6_ADDRSTRLEN]; 
    int rv; 

    memset(&hints, 0, sizeof hints); 
    hints.ai_family = AF_UNSPEC; 
    hints.ai_socktype = SOCK_STREAM; 
    hints.ai_flags = AI_PASSIVE; // use my IP 

    if ((rv = getaddrinfo(NULL, PORT, &hints, &servinfo)) != 0) { 
     fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); 
     return 1; 
    } 

    // loop through all the results and bind to the first we can 
    for(p = servinfo; p != NULL; p = p->ai_next) { 
     if ((sockfd = socket(p->ai_family, p->ai_socktype, 
         p->ai_protocol)) == -1) { 
      perror("server: socket"); 
      continue; 
     } 

     if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, 
        sizeof(int)) == -1) { 
      perror("setsockopt"); 
      exit(1); 
     } 

     if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) { 
      close(sockfd); 
      perror("server: bind"); 
      continue; 
     } 

     break; 
    } 

    if (p == NULL) { 
     fprintf(stderr, "server: failed to bind\n"); 
     return 2; 
    } 

    freeaddrinfo(servinfo); // all done with this structure 

    if (listen(sockfd, BACKLOG) == -1) { 
     perror("listen"); 
     exit(1); 
    } 

    sa.sa_handler = sigchld_handler; // reap all dead processes 
    sigemptyset(&sa.sa_mask); 
    sa.sa_flags = SA_RESTART; 
    if (sigaction(SIGCHLD, &sa, NULL) == -1) { 
     perror("sigaction"); 
     exit(1); 
    } 

    printf("server: waiting for connections...\n"); 

    while(1) { // main accept() loop 
     sin_size = sizeof their_addr; 
     new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size); 
     if (new_fd == -1) { 
      cout << "accept fail" << endl; 
      continue; 
     } 

     inet_ntop(their_addr.ss_family, 
       get_in_addr((struct sockaddr *)&their_addr), 
       s, sizeof s); 
     printf("server: got connection from %s\n", s); 

     if (!fork()) { // this is the child process 
      close(sockfd); // child doesn't need the listener 
      string response = "HTTP/1.0 200 OK\r\n\r\n<html><head><title>Test</title></head><body>ok!</body></html>"; 
      if (send(new_fd, response.c_str(), response.length(), 0) == -1) 
       cout << "error" << endl; 
      close(new_fd); 
      cout << "sent." << endl; 
      exit(0); 
     } 
     close(new_fd); // parent doesn't need this 
    } 

    return 0; 
} 

回答

3

因此,有這裏的2個錯誤(3真的,最後一個是,如果你想談論到瀏覽器你真的要好好其實現HTTP是不平凡)

  1. 您在接受客戶時立即發送回覆。瀏覽器有點慢可能會收到一個響應,甚至在它完成發送請求之前 - 這會混淆瀏覽器。

  2. 您沒有閱讀請求。這意味着,當你關閉套接字時,會有未讀數據,這將導致在關閉套接字時發送TCP RST(這會導致「連接重置...」錯誤)。在某些情況下,瀏覽器在發生之前會讀取響應,在其他情況下可能不會,(並且在某些情況下,由於您沒有Content-Length:標題,所以我猜它會混淆,所以瀏覽器不會不知道它是否應該在遇到TCP RST時接收更多數據)。這種特殊的情況進行說明更好here

+0

不將TCP RST取決於如何以及是否'''關機(2)'''被調用,而不是是否仍然未讀取的數據? – 2011-06-07 18:07:17

+0

是的,如果關閉()寫入方向,即使存在未讀數據也不會發送RST – Lyke 2011-06-07 19:07:03