2015-09-06 94 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

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