当前位置: 首页 > 知识库问答 >
问题:

套接字-在数据传输后保持套接字打开

夏侯自珍
2023-03-14

我编写了简单的服务器/客户端程序,其中客户端将一些硬编码数据以小块形式发送给服务器程序,服务器程序正在等待数据,以便将其打印到终端。在客户端,我在循环中调用send(),同时有更多的数据要发送,而在服务器上,我使用read()执行同样的操作,即返回的字节数为

如果我在完成发送后专门在客户端的套接字上调用close(),那么这个示例非常有效,但如果我不这样做,服务器将不会实际退出read()循环,直到我关闭客户端并断开连接。在服务器端,我使用:

while((bytesRead = read(socket, buffer, BUFFER_SIZE)) > 0)

当所有的数据都被接收到时,字节读不应该是0吗?如果是这样,为什么它不会退出这个循环,直到我关闭套接字?在我的最终应用程序中,在请求之间保持套接字打开将是有益的,但是所有的示例代码和信息我可以在发送数据后立即找到调用关闭(),这不是我想要的。

我错过了什么?

共有2个答案

钱锐
2023-03-14

您可以在recv调用上设置标志以防止阻塞。

一种轻松检测这种情况的方法是包装recv调用:

enum class read_result
{
    // note: numerically in increasing order of severity
    ok,
    would_block,
    end_of_file,
    error,
};

template<std::size_t BufferLength>
read_result read(int socket_fd, char (&buffer)[BufferLength], int& bytes_read)
{
    auto result = recv(socket_fd, buffer, BufferLength, MSG_DONTWAIT);
    if (result > 0)
    {
        return read_result::ok;
    }
    else if (result == 0)
    {
        return read_result::end_of_file;
    }
    else {

        auto err = errno;

        if (err == EAGAIN or err == EWOULDBLOCK) {
            return read_result::would_block;
        }
        else {
            return read_result ::error;
        }
    }
}

一个用例可能是:

#include <unistd.h>
#include <sys/socket.h>
#include <cstdlib>
#include <cerrno>
#include <iostream>

enum class read_result
{
    // note: numerically in increasing order of severity
    ok,
    would_block,
    end_of_file,
    error,
};

template<std::size_t BufferLength>
read_result read(int socket_fd, char (&buffer)[BufferLength], int& bytes_read)
{
    auto result = recv(socket_fd, buffer, BufferLength, MSG_DONTWAIT);
    if (result > 0)
    {
        return read_result::ok;
    }
    else if (result == 0)
    {
        return read_result::end_of_file;
    }
    else {

        auto err = errno;

        if (err == EAGAIN or err == EWOULDBLOCK) {
            return read_result::would_block;
        }
        else {
            return read_result ::error;
        }
    }
}

struct keep_reading
{
    keep_reading& operator=(read_result result)
    {
        result_ = result;
    }

    const operator bool() const {
        return result_ < read_result::end_of_file;
    }

    auto get_result() const -> read_result { return result_; }

private:
    read_result result_ = read_result::ok;
};

int main()
{
    int socket; // = open my socket and wait for it to be connected etc

    char buffer [1024];
    int bytes_read = 0;
    keep_reading should_keep_reading;
    while(keep_reading = read(socket, buffer, bytes_read))
    {
        if (should_keep_reading.get_result() != read_result::would_block) {
            // read things here
        }
        else {
            // idle processing here
        }
    }

    std::cout << "reason for stopping: " << should_keep_reading.get_result() << std::endl;
}
韩耘豪
2023-03-14

当套接字的另一端连接到地球另一端的其他网络系统时,接收套接字知道“何时接收到所有数据”的唯一方式正是套接字的另一边关闭的时候。这就是告诉套接字的另一边“所有数据都已收到”。

套接字所知道的只是它连接到其他某个套接字终结点。就是这样。故事结束。套接字对具有套接字连接另一端的程序的内部工作原理没有特殊知识。也不应该知道。这恰好是打开套接字的程序的责任,而不是套接字本身。

如果你的程序,在接收端,知道它应该接收什么数据,它现在已经收到了它需要接收的一切,那么它可以关闭它的套接字末端,然后继续手头的下一个任务。

您必须在程序的逻辑中加入一种方法,以某种形式或方式确定所有数据都已传输。它的确切性质将由你来定义。也许,在发送套接字上的所有数据之前,您的发送程序会在同一个套接字中预先发送后续数据中的字节数。然后,您的接收程序首先读取字节数,然后读取数据本身,然后知道它已经接收了所有内容,并且可以继续。

这是一种简单的方法。确切的细节取决于您。或者,您也可以实现超时:设置一个计时器,如果在规定的时间段内未收到任何数据,则假设没有更多数据。

 类似资料:
  • 我注意到netstat的套接字是打开的: 这是意料之中的行为吗?我是否需要显式地将连接头值设置为close以防止这种情况发生?

  • 我有两个服务器“A”(由我的朋友构建)和“B”(由我构建,使用Netty 4.1)。当客户端发送命令时,此服务器“A”和“B”会返回一些响应。我尝试使用简单的JAVA客户端套接字访问该服务器。以下是java客户端代码: 当将客户机连接到服务器A(非netty)时,方法会给出如下输出: 但是,当我尝试连接到服务器“B”(使用netty)时,输出如下: 为什么会发生这种情况?顺便说一下,在服务器B中,

  • 问题内容: 我是网络编程的新手。我有兴趣通过Java服务器和C客户端之间的套接字建立网络连接并保持连接无限打开的可能吗?我想保持连接打开状态以在客户端之间交换XML数据。 问题答案: 从理论上讲,可以无限期地打开服务器套接字;但是,使用客户端套接字是不可能的。主要原因是因为客户端套接字取决于处理数据的服务器端套接字,并且服务器套接字可能会关闭连接。 尽管可以无限期地保持连接打开,但实际情况通常会确

  • 问题内容: 我试图理解SocketChannels和NIO。我知道如何使用常规套接字,以及如何制作一个简单的每客户端线程服务器(使用常规阻塞套接字)。 所以我的问题是: 什么是SocketChannel? 当使用SocketChannel而不是Socket时,我还能得到什么呢? 通道和缓冲区之间是什么关系? 什么是选择器? 文档中的第一句话是。那是什么意思? 我也阅读了本文档,但是不知何故…… 问

  • socket_read和socket_recv之间有什么区别?我正在尝试使用PHP套接字,但使用socket_read时收到了以下警告: 请帮帮我!

  • 问题内容: 我正在尝试在Python中建立安全的套接字连接,而使用SSL有点麻烦。我已经找到一些有关如何与SSL建立连接的代码示例,但它们都涉及密钥文件。我尝试连接的服务器不需要接收任何密钥或证书。我的问题是,我该如何实质上包装带有SSL的python套接字连接。我知道我应该使用的密码是,协议是。这就是我一直在尝试的: 运行此代码时,没有任何错误,但响应为空。当尝试在命令行中调试此代码时,通过在终