2015-12-09 184 views
0

我使用套接字在c中製作服務器。客戶端向服務器發送請求。服務器解析併發回數據(html,png,jpg或bash腳本輸出)。我有一些關於它的問題。套接字服務器 - 將數據發送到客戶端

當我讀取html文件並將其發送到客戶端。如果文件很大,數據不發送和瀏覽器復位連接The connection was reset如何等待,直到所有數據都發送?在這個循環中。

while ((ret = read(html, buff, 1023)) > 0) 
{ 
    write(client_socketfd, buff, ret); 
} 

是否可以發送圖像(PNG或JPG)同樣的方式,如HTML,只改變HTML標題內容類型?

它是如何工作,如果在html文件中是一個標籤與src =「another.html」後點擊它客戶端發送GET請求?

如何在html文件中使用img標籤?

最後一個問題什麼是關閉無限循環服務器的最佳方法。在linux中,如果我關閉它與CTRL C套接字不關閉。

如果還有其他錯誤,我將不勝感激您的建議。

int main(int argc, char *argv[]) 
{ 
    int result; 
    int socket_desc, client_socketfd, c, read_size, buffer = 0; 
    struct sockaddr_in server, client; 
    char sprava[256]; 

    int arg; 

    int port = 0; 
    char *homeDir = NULL; 
    //get command line arguments -p port -d home dir 
    while ((arg = getopt(argc, argv, "p:d:")) != -1) { 
     switch (arg) { 
     case 'p': 
      port = atoi(optarg); 
      break; 
     case 'd': 
      homeDir = optarg; 
      break; 
     default: 
      fprintf(stderr, "Please speicify -p port and -d home directiory\n"); 
      exit(1); 
     } 
    } 

    if (port < 1500 || homeDir == NULL) { 
     fprintf(stderr, "BAD arguments use: -p port(greather then 1500) -d home dir\n"); 
     exit(1); 
    } 

    //Create socket 
    socket_desc = socket(AF_INET, SOCK_STREAM, 0); 
    if (socket_desc == -1) 
    { 
     printf("Could not create socket"); 
     return 1; 
    } 

    //Prepare the sockaddr_in structure 
    server.sin_family = AF_INET; 
    server.sin_addr.s_addr = INADDR_ANY; 
    server.sin_port = htons(port); 

    //Bind 
    if (bind(socket_desc, (struct sockaddr *)&server, sizeof(server)) < 0) 
    { 
     fprintf(stderr, "bind failed\n"); 
     exit(1); 
    } 

    printf("bind done\n"); 

    //Listen max 3 
    listen(socket_desc, 3); 

    //Accept and incoming connection 
    int loop = 1; 

    while (loop) { 
     printf("Waiting for incoming connections...\n"); 
     c = sizeof(struct sockaddr_in); 
     loop = 0; //only for testing, if everything run ok loop will be infinity 
     client_socketfd = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c); 
     if (client_socketfd < 0) { 
      fprintf(stderr, "Accept failed\n"); 
      exit(1); 
     } 
     //In child proc we are sending data 
     if (fork() == 0) { 
      close(socket_desc);//we dont need desc in child 
      bzero(sprava, 256);//all on '\0' 

     result = read(client_socketfd, sprava, 255); 
     printf("Server read: %s\n", sprava); 

     char* path; 
     int kod = parser(sprava, &path);//in path is path to file 
     if (kod == ERROR_FILE_TYPE) 
     { 
       printf("BAD request!!!!\n"); 
       shutdown(client_socketfd, SHUT_RDWR); 
       close(client_socketfd); 
      } 
      if (kod == HTML || kod == BASH || kod == JPG || kod == PNG) 
      { 
       if (kod == BASH) 
       { 
        FILE *pipe; 
        char *cmd = path; 
        strcat(cmd, " 2>&1");//error output send to pipe 
        printf("New command is=%s\n", cmd + 1);//we dont need first/
        //open pipe without first/
        pipe = popen(cmd + 1, "r"); 
        if (pipe != NULL) { 
         char text[1035]; 
         while (fgets(text, sizeof(text) - 1, pipe) != NULL) { 
          printf("output=%s", path); 
          write(client_socketfd, text, strlen(text)); 
         } 
        } 
        pclose(pipe); 
       } 
       else if (kod == HTML) 
       { 
        int html; 
        long len; 
        char buff[1024] = { 0 }; 
        int ret; 
        printf("Try to open file=%s\n", path + 1); 
        html = open(path + 1, O_RDONLY); 
        if (html == -1) { 
         fprintf(stderr, "Error opening file\n"); 
        } 
        len = (long)lseek(html, (off_t)0, SEEK_END);//len of file 
        lseek(html, (off_t)0, SEEK_SET); 
        sprintf(buff, "HTTP/1.1 200 OK\nServer: nweb/%d.0\nContent-Length: %ld\nConnection: close\nContent-Type: %s\n\n", 20, len, "text/html"); 
        //send html header to client 
        printf("Length of file=%d\n", len); 
        write(client_socketfd, buff, strlen(buff)); 
        printf("Header was send\n"); 
        while ((ret = read(html, buff, 1023)) > 0) 
        { 
         printf("number of bytes read=%d\n", ret); 
         //write data to client,it will make connection reset 
         write(client_socketfd, buff, ret); 
        } 
       } 
       free(path); 
      } 

      shutdown(client_socketfd, SHUT_RDWR); 
      close(client_socketfd); 
      exit(0); 

     } 
     //in parent close client 
     else { 
      close(client_socketfd); 
      wait(&wt);//this wait is only for testing 
     } 
    } 
    close(socket_desc); 
    return 0; 
} 
+0

http RFC(規範)在這裏:http://www.w3.org/Protocols/(7230至7235) – alk

+0

你也想爲你的每個問題提出一個SO問題。 – alk

+1

另請注意,從一個套接字讀取的read()不一定會返回儘可能多的字節數量,但很少。讀取次數*不需要與寫入次數匹配。仔細閱讀文檔。 – alk

回答

0

當我讀到的html文件,並將其發送給客戶端。如果文件大數據是 不發送和瀏覽器重置連接The connection was reset 如何等待,直到所有數據都發送?在這個循環中。

雖然您提到的循環有潛在的問題,但您的問題可能沒有答案。
我可以重現與您的代碼的問題,並經過一些搜索後,非常有趣的帖子The ultimate SO_LINGER page, or: why is my tcp not reliable。關鍵部分是從section 4.2.2.13 of RFC 1122這樣一句話:

如果在接收到的數據仍是 在TCP掛起這樣的主機發出CLOSE調用,或者,如果關閉後接收新數據被調用,其 TCP應該發送一個RST顯示數據丟失。

程序可能(在我的測試中,它)確實具有未決接收數據,因爲在對話開始它調用read(client_socketfd, sprava, 255),因此,如果HTTP GET請求超過255個字節,剩下的一部分請求待讀取的請求。現在,在所有發送數據已被提交到操作系統後的write之後,當調用close時,掛起的數據仍然存在,因此OS通過發送強制RST中止連接立即,可能會丟棄任何尚未傳送在其緩衝器中發送數據。因此,我們有一個令人驚訝的情況,即在開始時忽略接收導致最終傳輸數據丟失。
一個快速和髒的修復將增加sprava和字節數到read的大小,以便讀取整個請求 - 但請求的最大長度是多少?正確的方法是循環到read,直到請求被僅包含\r\n的空行終止。

相關問題