2016-11-17 2 views
2

В настоящее время я сталкиваюсь с некоторыми проблемами с моим проектом, и я надеюсь, что вы сможете идентифицировать мою проблему, поскольку я не способен ее увидеть сам.Отправка изображения через сокет и сохранение его на сервере

Я пытаюсь отправить изображение с C# Client (Windows) на мой C-сервер, работающий в Linux-системе. Я передаю двоичные данные изображения через TCP Socket, и это работает нормально, проблема в том, что когда я пишу полученный буфер в Linux-системе с помощью fwrite, кажется, что некоторая информация, которая присутствует в буфере, не является написанный или написанный с поврежденным значением в файл.

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 создает буфер поток ввода-вывода. Но вы не очищаете буфер и не закрываете файл. Вырезание проверку ошибок, вы делаете:

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) man-страница), fwrite сбрасывает его на диск (то есть выполняет системный вызов write(2)).

Однако, когда вы закончите, конец файла по-прежнему находится во внутреннем буфере, потому что библиотека не может знать, что вы закончили запись в файл, и вы этого не сделали находиться на границе BUFSIZ. Либо fflush, либо fclose расскажет библиотеке, чтобы очистить этот последний частичный буфер, записав его на диск.Затем с fclose базовый дескриптор файла ОС будет закрыт (что вы всегда должны делать в любом случае, или ваш сервер будет иметь «утечку дескриптора файла»).

+0

Я не мог видеть эту глупую ошибку. Большое спасибо! – Marcel

Смежные вопросы