2016-11-17 94 views
2

我目前面臨着我的項目中的一些問題,我希望你能夠識別我的問題,因爲我無法親自看到它。通過套接字發送圖像並將其保存在服務器上

我試圖從C#客戶端(Windows)發送圖片到我的C系統上運行的C服務器。我通過TCP套接字傳輸圖像二進制數據,工作得很好,問題是當我用fwrite在linux系統上寫入接收緩衝區時,似乎緩衝區中存在的一些信息不是寫入或寫入損壞的值到文件。

E.g.我試圖發送此圖片瀏覽:

enter image description here

這一個我得到的服務器上:

enter image description here

客戶端:

public static void sendPicture(Image image) 
    { 
     Byte[] imageBytes; 

     using (MemoryStream s = new MemoryStream()) 
     { 
      image.Save(s, ImageFormat.Jpeg); 
      imageBytes = s.ToArray(); 

      s.Close(); 
     } 

     if (imageBytes.Length <= 5242880) 
     { 
      try 
      { 
       NetworkStream stream = client.GetStream(); 

       File.WriteAllBytes("before.jpg", imageBytes); 

       //Send image Size 
       Byte[] imgSize = BitConverter.GetBytes((UInt32)imageBytes.Length); 

       stream.Write(imgSize, 0, imgSize.Length); 

       //Get answer from server if filesize is ok 
       Byte[] data = new Byte[1]; 
       // recv only looks if we have a partial read, 
       // works like stream.Read(data, 0, data.Length) 
       Int32 count = recv(stream, data, data.Length); 

       if (count != 1 || data[0] != 0x4) 
        return; 

       stream.Write(imageBytes, 0, imageBytes.Length); 

       ... 
      } 

服務器:

... 

    // INFO_BUFFER_SIZE (1) 
    buffer = malloc(INFO_BUFFER_SIZE); 

    // does allow parital reads 
    if (read_from_client(connfd, buffer, INFO_BUFFER_SIZE) == NULL) { 
     error_out(buffer, 
     "Error during receiv of client data @ read_from_client"); 
     close(connfd); 
     continue; 
    } 

    // reconstruct the image_size 
    uint32_t image_size = 
     buffer[3] << (0x8 * 3) | buffer[2] << (0x8 *2) | buffer[1] << 0x8 | 
     buffer[0]; 

    fprintf(stderr, "img size: %u\n", image_size); 

    // Check if file size is ok 
    if (check_control(image_size, 1, response) > 0) { 
     inform_and_close(connfd, response); 
     continue; 
    } 

    // Inform that the size is ok and we're ready to receive the image now 
    (void) send(connfd, response, CONT_BUFFER_SIZE, 0); 

    free(buffer); 
    buffer = malloc(image_size); 

    if (read_from_client(connfd, buffer, image_size) == NULL) { 
     error_out(buffer, 
     "Error during receiv of client data @ read_from_client"); 
     close(connfd); 
     continue; 
    } 

    FILE * f; 

    // Generate a GUID for the name 
    uuid_t guid; 
    uuid_generate_random(guid); 

    char filename[37]; 
    uuid_unparse(guid, filename); 

    if ((f = fopen(filename, "wb")) == NULL) { 
     inform_and_close(connfd, 0x0); 
     error_out(buffer, 
     "Error while trying to open a file to save the data"); 
     continue; 
    } 

    if (fwrite(buffer, sizeof(buffer[0]), image_size, f) != image_size) { 
     inform_and_close(connfd, 0x0); 
     error_out(buffer, "Error while writing to file"); 
     continue; 
    } 

    char output[100]; 
    (void) snprintf(output, sizeof(output), "mv %s uploads/%s.jpg", 
     filename, filename); 
    system(output); 

    free(buffer); 
    close(connfd); 

    ... 

如果我收到圖像並將其直接發送回客戶端和客戶端,然後將接收到的緩衝區寫入文件,則一切正常,發送的文件與接收到的文件沒有區別。正因爲如此,我相當確信變速器按預期工作。

如果您還需要更多,請告訴我!

回答

1

fopen創建一個緩衝 I/O流。但是你並沒有沖洗緩衝區並關閉文件。切割出的錯誤檢查,你正在做的:

f = fopen(filename, "wb"); 
fwrite(buffer, sizeof (buffer[0]), image_size, f); 

你應該在末尾添加這些:

fflush(f); 
fclose(f); 

fclose實際上將刷新你,但最好還是分開做沖洗,這樣你可以在關閉之前檢查錯誤。

這裏發生了什麼(有點過於簡單)是:

  1. fopen在磁盤上創建文件(使用open(2) [或creat(2)]系統調用),並分配一個內部緩衝區
  2. fwrite反覆填充內部緩衝。每次緩衝區填充到某個邊界(由BUFSIZ確定 - 請參閱setbuf(3)手冊頁),fwrite將其刷新到磁盤(即執行系統調用write(2))。

但是,當您完成後,文件的末尾仍然位於內部緩衝區中 - 因爲庫不知道您已經完成了寫入文件並且沒有發生在BUFSIZ邊界上。 fflushfclose會告訴庫清除最後的部分緩衝區,將其寫入磁盤..然後使用fclose底層操作系統文件描述符將被關閉(無論如何,您應該始終這樣做,否則您的服務器將出現「文件描述符泄漏」)。

+0

我無法看到那個愚蠢的錯誤。非常感謝! – Marcel

相關問題