2010-02-02 28 views
2

我正要通過網絡指南由Beej和很好奇的這部分代碼(特別是標有「從這裏開始」和「至此」):C:有關Beej的網絡指南的問題......這裏有一個假設嗎?

// main loop 
    for(;;) { 
     read_fds = master; // copy it 
     if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1) { 
      perror("select"); 
      exit(4); 
     } 

     // run through the existing connections looking for data to read 
     for(i = 0; i <= fdmax; i++) { 
      if (FD_ISSET(i, &read_fds)) { // we got one!! 
       if (i == listener) { 
        // handle new connections 
        addrlen = sizeof remoteaddr; 
        newfd = accept(listener, 
         (struct sockaddr *)&remoteaddr, 
         &addrlen); 

        if (newfd == -1) { 
         perror("accept"); 
        } else { 
         FD_SET(newfd, &master); // add to master set 
         if (newfd > fdmax) { // keep track of the max 
          fdmax = newfd; 
         } 
         printf("selectserver: new connection from %s on " 
          "socket %d\n", 
          inet_ntop(remoteaddr.ss_family, 
           get_in_addr((struct sockaddr*)&remoteaddr), 
           remoteIP, INET6_ADDRSTRLEN), 
          newfd); 
        } 
       } else { 
        // handle data from a client 
        //----------------- FROM HERE -------------------------- 
        if ((nbytes = recv(i, buf, sizeof buf, 0)) <= 0) { 
         // got error or connection closed by client 
         if (nbytes == 0) { 
          // connection closed 
          printf("selectserver: socket %d hung up\n", i); 
         } else { 
          perror("recv"); 
         } 
         close(i); // bye! 
         FD_CLR(i, &master); // remove from master set 
        //----------------- TO HERE ---------------------------- 
        } else { 
         // we got some data from a client 
         for(j = 0; j <= fdmax; j++) { 
          // send to everyone! 
          if (FD_ISSET(j, &master)) { 
           // except the listener and ourselves 
           if (j != listener && j != i) { 
            if (send(j, buf, nbytes, 0) == -1) { 
             perror("send"); 
            } 
           } 
          } 
         } 
        } 
       } // END handle data from client 
      } // END got new incoming connection 
     } // END looping through file descriptors 
    } // END for(;;)--and you thought it would never end! 

    return 0; 

現在我知道,閱讀沒有按」 t始終讀取要在套接字上讀取的「所有內容」,並且它有時只能返回其中的一部分。在這種情況下,這個代碼是不是不正確?我的意思是,在一次閱讀後,連接正在關閉......相反,我們是不是應該有其他一些機制?如果是這樣,這裏有什麼正確的方法?

+1

我前幾天看到的另一個教程似乎有相同的問題(http://www.ibm.com/developerworks/systems/library/es-nweb/sidefile1.html)。請注意它在「一次性」中讀取請求的部分。 – 2010-02-02 01:28:59

+0

有趣的..在一次性邏輯中的確切讀法......我想如果讓我們說要支持PUT命令,那真的會是一個問題。然後,我們需要先解析出標題,然後再決定是否要關閉連接。 – Legend 2010-02-02 01:31:21

+0

仔細閱讀,ThePosey是對的。套接字僅在發生錯誤時關閉。 – 2010-02-02 01:39:36

回答

4

套接字只會變得關閉如果recv()發生錯誤,那麼它會處理讀取的數據,即使它不是全部讀取的。當它再次循環時,它會讀出更多的信息。很確定這是你問的問題?

+0

哦,我在問代碼是如何假設所有的數據都是一次性讀取的......如果它沒有讀取所有的東西這有一個明確的關閉線來關閉連接...然後數據是「丟失」... – Legend 2010-02-02 01:32:37

+0

只有當關閉只發生數據沒有數據留下來讀取或收到錯誤 – ThePosey 2010-02-02 01:37:17

+0

哦!!我的壞。 ..我真的沒有很注意那裏的其他條件... – Legend 2010-02-02 01:40:04

1

是的,你會繼續讀書,直到你得到你所期望的數據,obviosuly需要好歹知道如何值得期待的 - 這就是爲什麼HTTP把文件的大小第一

+0

這確實是一個非常聰明的決定,所以幾乎必須讓我們把這樣一條線放在任何位置我們設計的協議是什麼? – Legend 2010-02-02 01:27:51

+1

或者你有固定大小的消息,或一些明顯的消息符號結束 - 這取決於你的應用程序。對於http/ftp,你知道你發送的文件的大小,對於視頻會議來說,不同的方法最好是 – 2010-02-02 01:30:33

+0

@Legend:不,不是。在一個典型的情況下,你閱讀,直到你得到一個返回<= 0,表明你已經到達流的末尾或者還有其他類型的錯誤。 – 2010-02-02 01:31:39

1

你只有在recv()返回一個負值時纔會調用close,這意味着recv有某種錯誤。請注意,您關閉的區域有註釋,說明// got error or connection closed by client)。

當您實際獲得一些數據(else支持從// we got some data from a client開始)時,連接未關閉。

你是對的,你不能假設數據一次全部到達。您的錯誤在於遵循代碼的工作方式。

+0

Yeap剛剛意識到我用正確的一段代碼問了問題:) – Legend 2010-02-02 01:43:20