【问题标题】:How to send image data over linux socket如何通过 linux 套接字发送图像数据
【发布时间】:2015-12-02 06:39:40
【问题描述】:

我有一个用 C++ 编写的相对简单的 Web 服务器。它适用于提供文本/html页面,但它的编写方式似乎无法发送二进制数据,我真的需要能够发送图像。

我一直在搜索和搜索,但找不到特定于这个问题的答案,它是用真正的 C++ 编写的(fstream,而不是使用文件指针等),虽然这种事情必然是低级的,而且很可能需要处理 C 样式数组中的字节我希望代码尽可能 C++。

我尝试了几种方法,这是我目前拥有的:

int sendFile(const Server* serv, const ssocks::Response& response, int fd)
{
// some other stuff to do with headers etc. ........ then:

    // open file
    std::ifstream fileHandle;
    fileHandle.open(serv->mBase + WWW_D + resource.c_str(), std::ios::binary);

    if(!fileHandle.is_open())
    {            
        // error handling code
        return -1;
    }

    // send file
    ssize_t buffer_size = 2048;
    char buffer[buffer_size];

    while(!fileHandle.eof())
    {
        fileHandle.read(buffer, buffer_size);

        status = serv->mSock.doSend(buffer, fd);
        if (status == -1)
        {
            std::cerr << "Error: socket error, sending file\n";
            return -1;
        }
    }
    return 0
}

然后在其他地方:

int TcpSocket::doSend(const char* message, int fd) const
{
    if (fd == 0)
    {
         fd = mFiledes;
    }

    ssize_t bytesSent = send(fd, message, strlen(message), 0);
    if (bytesSent < 1)
    {
        return -1;
    }

    return 0;
}

正如我所说,问题是当客户端请求图像时它不会工作。我进入 std::cerr “错误:套接字错误发送文件”

编辑:我使用我接受的答案中的建议让它工作。为了完整起见并帮助那些找到这篇文章的人,我还发布了最终的工作代码。

对于发送,我决定使用 std::vector 而不是 char 数组。主要是因为我觉得它是一种更 C++ 的方法,并且清楚地表明数据不是字符串。这可能不是必需的,而是一个品味问题。然后我计算了为流读取的字节数,并将其传递给发送函数,如下所示:

// send file
std::vector<char> buffer(SEND_BUFFER);
while(!fileHandle.eof())
{
    fileHandle.read(&buffer[0], SEND_BUFFER);
    status = serv->mSock.doSend(&buffer[0], fd, fileHandle.gcount());
    if (status == -1)
    {
        std::cerr << "Error: socket error, sending file\n";
        return -1;
    }
}

然后实际的发送函数是这样改编的:

int TcpSocket::doSend(const char* message, int fd, size_t size) const
{
    if (fd == 0)
    {
        fd = mFiledes;
    }

    ssize_t bytesSent = send(fd, message, size, 0);
    if (bytesSent < 1)
    {
        return -1;
    }

    return 0;
}

【问题讨论】:

    标签: c++ linux sockets


    【解决方案1】:

    您应该更改的第一件事是while (!fileHandle.eof()) 循环,因为它不会像您期望的那样工作,实际上它会迭代一次太多,因为直到您尝试之后才会设置eof 标志从文件末尾之外读取。相反,例如while (fileHandle.read(...)).

    您应该做的第二件事是检查从文件中实际读取了多少字节,并且只发送该数量的字节。

    最后,您读取的是二进制数据,而不是文本,因此您不能对从文件中读取的数据使用strlen


    对二进制文件问题的一点解释:如您所愿,C 风格的字符串(您使用 strlen 来获取长度的字符串)以零字符 '\0' 结尾(简而言之,零字节)。随机二进制数据可以包含大量的零字节,它是一个有效字节,没有任何特殊含义。

    当你使用strlen获取二进制数据的长度时有两个可能的问题:

    1. 数据中间有一个零字节。这将导致strlen 提前终止并返回错误的长度。

    2. 数据中有没有个零字节。这将导致strlen 超出缓冲区的末尾以查找零字节,从而导致未定义的行为

    【讨论】:

    • 我尝试按照建议使用 while(fileHandle.read(...)) 但它现在不读取整个文件。当我发送文本页面时 - 它现在不发送最终包裹。另外我想知道您是否可以提供一些代码示例。我对 C++ 比较陌生,所以可能不会像您预期的那样迅速接受这个想法!例如,我应该如何计算从 fileHandle 读取的字节数?谢谢
    • @SamRedway 我建议您查看this excellent reference,并仔细查看std::basic_istream 参考,并查找gcount 成员函数。
    猜你喜欢
    • 2013-12-31
    • 1970-01-01
    • 1970-01-01
    • 2011-04-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多