2013-12-04 5 views
0

Я некоторое время застрял в этой проблеме, где я не могу отправить файл через сокет. Я просто передал другую информацию, используя этот метод, но проблема возникает, когда я пытаюсь отправить PNG-файл в виде строки.Ошибка сокета при отправке файла

Это методы, которые я использую, чтобы отправлять и получать информацию:

// Sends a Message to the specified Socket 
void Server::sendMessage(int socket, string message) 
{ 
    // Write the Message Size to the Socket 
    send(socket, itoa((message.length() + 1)), sizeof(size_t)); 

    // Wait for Write Confirmation 
    bool response; 
    receive(socket, &response, 2); 

    // Write the Message to the Socket 
    send(socket, (char*) message.c_str(), message.length() + 1); 

    // Wait for Write Confirmation 
    receive(socket, &response, 2); 
} 

// Receives Message from the specified Socket 
string Server::receiveMessage(int socket) 
{ 
    // Read the Message Size from the Socket 
    int size; 
    receive(socket, &size, sizeof(size_t)); 

    // Send Write Confirmation 
    send(socket, itoa(true), 2); 

    // Receive the Message from the Socket 
    char message[size]; 
    receive(socket, message, size); 

    // Send Write Confirmation 
    send(socket, itoa(true), 2); 

    // Return the Message as a String 
    string msg(message); 
    return msg; 
} 

отправить и получить методы только реле для записи и чтения соответственно. Я только делаю проверку ошибок в этих методах, и это отправьте метод, который говорит мне, что пишет не работает. В случае, если это имеет значение, это мой отправить метод:

// Sends a Data Packet to the specified Socket 
int Server::send(int socket, void* data, int size) 
{ 
    // Write the Data to the Socket 
    int count = write(socket, data, size); 

    // Make sure the Write Succeeded 
    if(count == -1) 
    { 
      print("$f1Error: $f0Unable to Write to Socket $t1%i$t0\n", socket); 
      exit(1); 
    } 

    return count; 
} 

Я хотел бы отметить, что сервер работает как Thread, поэтому приведенные выше три функции являются статическими. Клиент также содержит те же четыре сетевых функции.

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

// Handles each Client with a Thread 
void* Server::server_handleClient(void* arg) 
{ 
    // Determine the Socket Descriptor 
    int socket = *((int*) arg); 
    free(arg); 

    // Create the Rover 
    Rover* rover = new Rover(); 

    // Loop Indefinitely 
    while(true) 
    { 
     ... 
     // Take a Picture and Send it 
     sendMessage(socket, rover -> takePicture()); 
     ... 
    } 

    // Delete the Rover 
    delete rover; 

    // Close the Socket 
    close(socket); 

    // Return a Successful Status 
    return (void*) new int(0); 
} 

Здесь вы можете увидеть, что я использую метод из другого класса я создал. Вот takePicture метод от Rover класса, который является, где я на самом деле захватить картину:

// Takes a Picture and Returns the Photo as a String 
inline string Rover::takePicture() 
{ 
    // Open the Picture File 
    ifstream picture; 
    string filepath = "./Server/Pictures/" + getDirection() + ".png"; 
    picture.open(filepath.c_str()); 

    // Make sure the File Opened 
    if(!picture.is_open()) 
      return ""; 

    // Read the File into a String Buffer 
    stringstream buffer; 
    buffer << picture.rdbuf(); 

    return buffer.str(); 
} 

Таким образом, в общем, сервер получает изображение от Rover который затем посылает до Клиент. Когда я проверяю содержимое строки для фотографии, это все. Все возможные фотографии являются разумными по размеру (фотография, используемая для тестирования, составляет 674,962 байт, а размер отправляемого буфера составляет 674,963, что ожидается).

Я использовал эти методы для отправки различных сообщений, и все это отлично работало. Я могу отправить строки (Как «Hello World!») и целые числа просто отлично.

Есть ли что-то, что я делаю неправильно? Является ли файл, который я пытаюсь отправить просто слишком большим? Есть ли какая-то информация, которую мне не хватает? Мне нужна помощь ...


Edit: Я сделал несколько изменений, с небольшим прогрессом. Я сделал небольшое изменение команды sendMessage. Текущая проблема заключается в том, что изображение не отправляется должным образом.

Новый SendMessage функция: копия

// Sends a Message to the specified Socket 
void Server::sendMessage(int socket, string message, bool data = false) 
{ 
     // Write the Message Size to the Socket 
     send(socket, itoa((message.length() + 1)), sizeof(size_t)); 

     // Wait for Write Confirmation 
     bool response; 
     receive(socket, &response, 2); 

     // Determine the Type of Data to Send 
     if(data) 
     { 
       // Write the Message Data to the Socket 
       send(socket, (char*) message.data(), message.length() + 1); 
     } 
     else 
     { 
       // Write the Message to the Socket 
       send(socket, (char*) message.c_str(), message.length() + 1); 
     } 

     // Wait for Write Confirmation 
     receive(socket, &response, 2); 
} 

Клиента этой функции была обновлена, чтобы соответствовать, а также.

Теперь, когда мы работаем над получением файла PNG сохранен, вот функция, которая имеет дело с тем, как хорошо:

// Handles each Client with a Thread 
void* Client::client_handleServer(void* arg) 
{ 
     // Define Socket Variables 
     int socket = *((int*) arg); 
     free(arg); 

     ... 
     // Export the Picture to the Client's Directory 
     message = receiveMessage(socket); 
     ofstream picture; 
     picture.open("./Client/Pictures/Picture.png", std::ifstream::binary); 
     picture << message; 
     picture.close(); 
     ... 
} 
+0

Вы не описали, что происходит с изображением на стороне клиента? почему вы отправляете message.length() + 1? – goldcode

+0

Я отправляю сообщение до отправки сообщения, чтобы другая система знала, сколько читать. Что касается изображения на стороне клиента, запись на стороне сервера не удалась, поэтому клиент так и не получил его. Код показывает это, поскольку ошибка возникает только в том случае, если количество байтов, записанных в сокет, равно -1 (это означает, что запись не удалась). – Boom

ответ

0

В конечном итоге я в конечном итоге все понял.

Фотографии - это двоичные файлы, и я использовал строки, которые используют символы ASCII. Проблема заключается в том, что двоичные данные не всегда переводятся в ASCII, а строки заканчиваются нулевыми символами, тогда как двоичные данные могут содержать нулевые данные внутри него. Короче говоря, строки не работают.

Чтобы сохранить обработку сообщений, которые у меня были на месте, я просто преобразовал двоичные данные в шестнадцатеричные данные (0-F), которые могут отображаться в строке.

1

В настоящее время вы открываете файл в текстовом режиме. это означает, что любые символы в файлах, которые содержат символы новой строки «\ n», преобразуются в новую строку + возврат каретки «\ r \ n».

Откройте файл в двоичном режиме, как и

picture.open(filepath.c_str(), std::ifstream::binary); 

, то он может работать.

+0

Я пробовал это и немного продвинулся вперед. Запись больше не терпит неудачу, но передается только 8 байт (сервер по-прежнему отправляет нужную сумму). Когда я проверяю отправленную строку, она содержит следующее: «% PNG [] \ n \ n \ 0". «[]» - это всего лишь символ коробки, считающийся одним символом. Если я попытаюсь открыть изображение в Paint, это говорит о том, что PNG не является допустимым форматом, и он не может его прочитать. – Boom

+0

// Запись сообщения на сокет send (socket, (char *) message.c_str(), message.length() + 1); dont конвертировать в c_str(). вместо этого используйте message.data(). message.c_str() преобразует его в строку C с нулевым завершением. – goldcode

+0

Просто попробовал это. Вывод слегка отличается, и изображение по-прежнему не передается должным образом. Отправленное сообщение теперь «‰ PNG \ n [] \ n \ 0". Разница в одном значении (я потерял первое место \ n). – Boom

1
void Server::sendMessage(int socket, string message) 

Проблема здесь. Не используйте string в качестве контейнера для двоичных данных. Передайте изображение как массив байтов. То же самое относится к этому:

string Server::receiveMessage(int socket) 
Смежные вопросы