2016-04-11 3 views
-1

Согласно this solution для отправки изображения через TCP. Поскольку код очень элегантный по сравнению с другими способами, и оба изображения и файла являются данными, я считаю, что мы можем использовать почти тот же код для отправки файла.C Ошибка передачи файлов сокета

Так что если я хочу отправить файл с клиента на сервер.

На клиента стороны

  1. размер на файл
  2. посыла размер файла // Вышеуказанные действия всегда будут работать, так что я буду показывать только код после того, как здесь
  3. содержимого файла для чтения в буфер

    char buf[size]; 
    read(fs,buf,size); 
    
  4. отправьте буфер

    int bytes = 0; 
    for (uint i = 0;i<size;i+=bytes) 
    { 
        if ((bytes = send(sock,buf+i,size-i,0))<0) 
        { 
         fprintf(stderr,"Can not send file\n"); 
         close(fd); 
         return false; 
        } 
        fprintf(stderr,"bytes write = %d\n",bytes); 
    } 
    

А на сервере стороне

  1. размер RECV файла
  2. RECV материал в буфер с размером от шага буфера 1

    char buf[size]; 
    int bytes=0; 
    for (uint i = 0;i<size;i+=bytes) 
    { 
        if ((bytes = recv(sock,buf+i,size-i,0))<0) 
        { 
         fprintf(stderr,"Can not receive file\n"); 
         return false; 
        } 
        fprintf(stderr,"bytes read = %d\n",bytes); 
    } 
    
  3. записи к файлу

    fwrite(buf,sizeof(char),size,fs); 
    

Этот код будет компилироваться и работать.

Когда я отправляю двоичный файл cpp (24k) с клиента на сервер, так как клиент и сервер находятся на одном компьютере (OS X), этот двоичный файл будет получен и может быть выполнен.

Но если сервер пересылает файл обратно клиенту и клиент пересылает этот файл на сервер несколько раз, этот двоичный файл будет поврежден. Но количество отправленных байтов и количество полученных байтов совпадают, а размер файла по-прежнему равен 24k.

Мне интересно, что здесь происходит.

Является ли это ошибкой ОС?

Спасибо,

+0

Ваш код 'recv()' не обрабатывает неожиданный конец потока правильно. Цикл должен заканчиваться, если 'recv()' возвращает ноль или -1. И если вы получите сообщение об ошибке из 'send()' или 'recv()', то не достаточно просто распечатать собственное сообщение. Вы должны получить фактическую ошибку там где-нибудь, с 'perror()' или 'strerror()'. – EJP

+0

Да. Я должен. Из кода, который у меня выше, если 'recv()'/'send()' return -1, то функция завершится. Если они возвращают 0, тогда он должен печатать число байтов recv/send равно 0. Но такое сообщение не было распечатано, когда сбой переданного двоичного файла. – Ling

+0

Вы уверены, что buf размер большой? (Так как пример не завершен, и в его текущей форме он выглядит okey). Если вы hexdump поврежденный файл, какой вид вы видите? У вас есть доступность? Это всегда удобно, что может обнаружить некоторые проблемы с памятью. –

ответ

-1

Если оба клиента и сервер находятся в одной папке, то в этом случае это похоже на копирование и вставку файла.

Так что, когда клиент отправить файл, он будет

  1. открыть файл
  2. имени файла
  3. прибудут/размера + отправить имя/размер + отправить данные
  4. закрыть файл

На серверная сторона,

  1. получить имя/размер файла
  2. открыть тот же файл снова
  3. прибудете содержимое файла
  4. закрыть файл

Таким образом, проблема будет происходить на шаге 2, вызывая состояние гонки.

+0

Это не состояние гонки, и в вашем вопросе нет никаких доказательств того, что вы отправляете и получаете тот же файл, или даже этот клиент и сервер работают на одном хосте. – EJP

2

Ни send(), ни recv(), гарантирует, что количество байтов, запрошенных на самом деле будет отправлено или получено. В этом случае возвращаемое значение будет по-прежнему положительным, но меньше количества байтов, запрошенных в системном вызове.

Это подробно описано в документации на страницу руководства для send() и recv(). Пожалуйста, перечитайте документацию вашей операционной системы для этого системного вызова.

Обязанностью приложения является попытка повторить попытку отправки или получения оставшихся байтов.

Этот код предполагает, что количество отправленных байтов - это количество запрошенных им байтов. Кажется, что он правильно обрабатывает статус возврата recv(), но не send(). После того, как было отправлено меньшее количество байтов, этот код по-прежнему предполагает, что все содержимое было отправлено или получено, а системный вызов fwrite() закончится написанием нежелательной почты вместо последней части файла.

+0

Привет, я добавил код для обработки 'send()'. Но проблема остается. И когда это не удается, размер файла (клиентская сторона) = # данных write = # данных read = размер файла (на стороне сервера). Есть идеи? – Ling