【问题标题】:C: Question about Beej's networking guide... Is there an assumption here?C:关于Beej 的网络指南的问题......这里有假设吗?
【发布时间】:2010-02-02 01:24:05
【问题描述】:

我刚刚浏览了 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;

现在我知道 read 并不总是读取要在套接字上读取的“所有内容”,并且有时只能返回其中的一部分。在那种情况下,这段代码不会不正确吗?我的意思是,读完之后,连接就被关闭了……相反,我们不应该有一些其他的机制吗?如果是这样,这里的正确方法是什么?

【问题讨论】:

  • 我几天前阅读的另一个教程似乎有同样的问题 (ibm.com/developerworks/systems/library/es-nweb/sidefile1.html)。请注意它“一次性”读取请求的部分。
  • 有趣.. 一次性逻辑中的确切读取... 我认为当我们想要支持 PUT 命令时,这确实是一个问题。然后我们需要先解析出headers,然后再决定是否要关闭连接。
  • 仔细阅读,ThePosey 是对的。套接字仅在出错时关闭。
  • 是的......我错了......我太仓促了,并没有真正专注于那里的其他条件...... :)

标签: c networking sockets select


【解决方案1】:

只有当recv() 出错时,socket 才会在那里关闭,否则即使没有全部读取,它也会处理读取的数据。当它再次循环时,它将读取更多内容。很确定这是您要问的?

【讨论】:

  • 哦,我在问代码是如何假设一次性读取所有数据的...如果它没有读取有明确关闭行的整个内容会发生什么关闭连接...然后数据“丢失”...
  • 只有在没有数据要读取或recv出现错误时才会关闭。
  • 哦!我的错...我并没有真正关注那里的 else 条件...
  • 是的,C 套接字代码几乎永远循环,直到发生不好的事情或有人关闭连接。
【解决方案2】:

是的,你会一直阅读,直到你得到你所期望的所有数据,显然你需要以某种方式知道期望有多少——这就是为什么 http 将文档大小放在首位的原因

【讨论】:

  • 这确实是一个非常明智的决定,因此我们几乎有必要在我们设计的任何协议中加入这样一条线是吗?
  • 或者你有固定大小的消息,或者一些明显的消息符号结尾——这取决于你的应用程序。对于 http/ftp,您知道要发送的文件的大小,对于视频会议,最好采用不同的方法
  • @Legend:不,不是。在典型情况下,您会一直阅读,直到收到返回
  • 并非如此。想想例如 VoIP。不可能知道对话会持续多久。您只需处理来自套接字的传入音频数据,并在完成后以某种方式关闭连接。
  • @Legend - 你并不总是想在每条消息后关闭袜子。 Http 这样做是为了让 Web 服务器不需要为数百万个浏览器中的每一个保持打开套接字 - 但对于不同的点对点应用程序,保持打开并标记消息的结尾是有意义的
【解决方案3】:

当 recv() 返回负值时,您唯一的调用 close 意味着 recv 有某种错误。请注意,您关闭的块有一条注释说明// got error or connection closed by client)。

当你实际得到一些数据时(else 分支以// we got some data from a client 开头),连接并没有被关闭。

您是对的,您不能假设数据一次全部到达。您的错误在于遵循代码的工作方式。

【讨论】:

  • 是的,我刚刚意识到我用正确的代码问了这个问题 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-08
  • 2011-04-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多