2015-09-06 96 views
0

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

我一直在寻找和搜索,但无法找到一个特定于这个问题的答案,它是用真正的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; 
} 

回答

3

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

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

最后,你读二进制数据,而不是文本,所以你不能使用strlen你从文件中读取的数据。


二进制文件问题的一个小的解释:正如你应该有希望知道,C风格的字符串(您使用strlen获得的长度的)由零字符'\0'终止(简而言之,零字节)。随机二进制数据可以在其中的任何位置包含大量零字节,并且它是有效的字节,并且没有任何特殊含义。

当您使用strlen得到的二进制数据的长度有两种可能出现的问题:

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

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

+0

我尝试使用while(fileHandle.read(...))建议,但它现在不读取整个文件。当我发送一个文本页面时 - 它现在不发送最终的包裹。另外我想知道你能否给出一些代码示例。我相对较新的C++,所以可能不会像你所期望的那样快速地实现这个想法!例如,我应该如何计算从fileHandle读取的字节数?谢谢 –

+1

@SamRedway我建议你看看[这个优秀的参考资料](http://en.cppreference.com/w/cpp),并且仔细看看['std :: basic_istream'](http: //en.cppreference.com/w/cpp/io/basic_istream)引用,并查找['gcount'](http://en.cppreference.com/w/cpp/io/basic_istream/gcount)成员函数。 –

+0

非常好,我得到它的工作。谢谢 –