c - tcp 指示流结束

标签 c tcp stream

我无法结束 TCP 流。我正在编写一个简单的服务器和客户端,其中客户端连接到服务器并且服务器显示一条欢迎消息,要求客户端输入用户名。

问题是,当服务器写入消息时,客户端的 read() 被阻塞。它只有在我调用 shutdown() 时才会解锁。

服务器:

           if (FD_ISSET(tcp_listenfd, &rset)) {
                  len = sizeof(cliaddr);
                  if ((new_confd = accept(tcp_listenfd, (struct sockaddr *) &cliaddr, &len)) < 0) {
                            perror("accept");
                            exit(1);
                  }
                  /* Send connection message asking for handle */
                  writen(new_confd, handle_msg, strlen(handle_msg));
                  /* Fork here or shutdown fd is inherited */
                  shutdown(new_confd, SHUT_WR);

客户:

    if ((connect(sock, (struct sockaddr *) server, sizeof(struct sockaddr_in))) < 0) {
            perror("inet_wstream:connect");
            exit(1);
    }

    s_welcome_msg[19] = '\0';
    readn(sock, s_welcome_msg, 20); //Blocks here if shutdown() is not called in server 

readn()writen() 函数改编自 Stevens 的“The Socket Networking API”,可在此处找到:http://www.informit.com/articles/article.aspx?p=169505&seqNum=9

如何在不调用 shutdown() 且不让客户端阻塞的情况下从服务器编写欢迎消息?如果需要更多上下文,我将发布更多代码。

最佳答案

请注意,readn() 设计为循环read(),直到读取了 20 个字节或出现 EOF 或套接字错误。如果服务器发送的消息长度小于 20 个字节,客户端将阻塞等待更多数据。

为防止阻塞,您可以在套接字上执行普通的read()(或recv())。在这种情况下,这很可能会满足您的要求。

不过,一般来说,您不能依赖于将 write()read() 配对用于 TCP 连接。字符串“bar”的单个 write() 可以任意拆分数据。作为一个极端的例子,三个连续的 read() 可能会返回“b”、“a”和“r”。该特定示例不太可能,但对于较大的 write()read(),您必须考虑到这一点(对于较小的传输,如果您想绝对安全)。

要解决此问题,您必须在接收端进行自己的缓冲。在这种情况下,最简单的解决方案是一次 read() 一个字符(或者使用 readn() 与您期望的数据量,如果它是已知的).一个更通用的解决方案是 read() 尽可能多的数据(确保检查 read() 的返回值以查看您返回了多少数据!) 放入缓冲区,并且仅在收集到足够的数据时才对数据进行操作。只要有一些数据可供读取,普通的read() 就不会阻塞,但您取回的数据可能少于您请求的数据。

“够了”通常是您协议(protocol)中的完整“消息”。您将需要一些方法来确定消息边界。两种选择是长度字段(根据我的经验通常是最好的解决方案)或消息终止符。两者都将与其余数据一起发送。

更新:

顺便说一句,你的空终止逻辑有一个错误。将 20 个字节读入 s_welcome_msg 会将 s_welcome_msg[19] 设置为最后读取的字节,覆盖空终止符。如果要将 20 字节的非空终止字符串读入 s_welcome_msg 并以空终止它,s_welcome_msg 需要 21 字节长,并且您需要执行 s_welcome_msg[20] = '\0'

关于c - tcp 指示流结束,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29189821/

相关文章:

c - Unix 套接字,SOCK_SEQPACKET 与 SOCK_DGRAM

android - 通过套接字查看 Web 服务器。 . .

c# - 网络流如何检测断开连接

go - GCP语音到文本和语音激活检测协同工作

audio - 使用Red5媒体服务器播放音频

android - 如何从网页启动 Android 的 Native MediaPlayer?

c - strcat() 在使用 gcc 的 xcode 中出现问题

c++ - 确定 HWND 是否代表顶级窗口的最佳方法是什么?

c - 为什么 putchar 打印的是一些数值而不是我要求它输入的字符?

c# - 如何从 Socket 获取 IP 地址