2010-02-02 32 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