2013-05-10 4 views
1

Я не уверен в некоторых вещах относительно передачи файлов ftp. Я пишу ftp-сервер, и я пытаюсь выяснить, как сделать файл tranfer работать правильно. Пока это работает как-то, но у меня есть определенные сомнения. Вот моя функция передачи файлов (только до сих пор):Передача файла FTP-сервера

void RETRCommand(int & clie_sock, int & c_data_sock, char buffer[]){ 
ifstream file; //clie_sock is used for commands and c_data_sock for data transfer 
char *file_name, packet[PACKET_SIZE]; //packet size is 2040 
int packet_len, pre_pos = 0, file_end; 
file_name = new char[strlen(buffer + 5)]; 
strcpy(file_name, buffer + 5); 

sprintf(buffer, "150 Opening BINARY mode data connection for file transfer\r\n"); 

if (send(clie_sock, buffer, strlen(buffer), 0) == -1) { 
    perror("Error while writing "); 
    close(clie_sock); 
    exit(1); 
} 

cout << "sent: " << buffer << endl; 

file_name[strlen(file_name) - 2] = '\0'; 
file.open(file_name, ios::in | ios::binary); 

if (file.is_open()) { 

    file.seekg(0, file.end); 
    file_end = (int) file.tellg(); 
    file.seekg(0, file.beg); 

    while(file.good()){ 

     pre_pos = file.tellg(); 
     file.read(packet, PACKET_SIZE); 

     if ((int) file.tellg() == -1) 
      packet_len = file_end - pre_pos; 
     else 
      packet_len = PACKET_SIZE; 

     if (send(c_data_sock, packet, packet_len, 0) == -1) { 
      perror("Error while writing "); 
      close(clie_sock); 
      exit(1); 
     } 

     cout << "sent some data" << endl; 

    } 

} 
else { 
    sprintf(buffer, "550 Requested action not taken. File unavailable\r\n", packet); 

    if (send(clie_sock, buffer, packet_len + 2, 0) == -1) { 
     perror("Error while writing "); 
     close(clie_sock); 
     exit(1); 
    } 

    cout << "sent: " << buffer << endl; 

    delete(file_name); 
    return; 
} 

sprintf(buffer, "226 Transfer complete\r\n"); 

if (send(clie_sock, buffer, strlen(buffer), 0) == -1) { 
    perror("Error while writing "); 
    close(clie_sock); 
    exit(1); 
} 

cout << "sent: " << buffer << endl; 

close(c_data_sock); 

delete(file_name); 
} 

Таким образом, одной из проблем является сама передача данных. Я не совсем уверен, как он должен работать. Теперь он работает следующим образом: сервер отправляет все данные в c_data_sock, закрывает этот сокет, а затем клиент начинает что-то делать. Не должен ли клиент получать данные, пока сервер их отправляет? Другая проблема - команда abor. Как я должен получить команду abor? Я попробовал recv с флагом, установленным в MSG_OOB, но затем я получаю сообщение об ошибке «Недопустимый аргумент». Я был бы рад, если бы кто-нибудь мог дать мне подсказку или пример того, как это сделать правильно, поскольку я, похоже, не могу понять это сам.

Спасибо,

Джон

+0

любая причина не использовать 'libftp или libCurl'? – billz

+0

I naïvely пошел бы с «он учится» –

+0

Хорошо спасибо за предложение, но это назначение класса, и я не могу использовать какие-либо дополнительные библиотеки. Однако я мог бы взглянуть на источник. – user2274361

ответ

0

Ftp использовать два соединения. Первое - это командная связь, в вашем случае это clie_sock. Команда «ABOR» должна быть получена, хотя она. Вы получите его так же, как вы получили команду «RETR». Для получения файла клиент устанавливает соединение с вашим сервером (сокет c_data_sock). Он не будет открыт, пока клиент не подключится, так что это ответ на ваш второй вопрос. Вы не можете запустить клиент после выполнения этой функцией сервера. Первый клиент отправляет команду «retrieve» в ваш командный сокет. Затем ваш сервер ждет нового подключения от клиента (после отправки ему данных ip и port). Затем клиент подключается (теперь у вас есть готовый c_data_sock) и отправляет все данные в этот сокет, которые в свою очередь принимаются клиентом.

Возможно, вам, скорее всего, нужно больше узнать о сети, если вы чувствуете, что не понимаете этого. Я предпочитаю это один: http://beej.us/guide/bgnet/

Также у вас есть утечка памяти здесь, после того, как вы выделяете массив с

file_name = new char[strlen(buffer + 5)]; 

вам необходимо удалить его с помощью

delete [] file_name; 

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

+0

Спасибо за ваш ответ. Что же касается получения abor, у меня должна быть функция recv после функции отправки, чтобы проверить, отправлен ли клиент abor? Тогда мне нужно будет добавить тайм-аут к этому recv, чтобы цикл мог продолжать или есть другой способ? Кстати, когда я прерываю передачу файла, сервер ничего не получает. – user2274361