2017-01-10 1 views
0

Реализация TFTP-клиента через сокет UDP. Сначала я создаю неблокирующий сокет UDP и выполняю операцию PUT/GET, он отлично работает. Но когда я снова пытаюсь выполнить GET/PUT, он не работает. Сам запрос RRQ/WRQ не доходит до сервера, но с клиентской стороны он успешно отправлен. Ниже приведен код клиента tftp.Второе время TFTP PUT opearation не работает после того, как команда GET/PUT успешно закончила первый раз на стороне клиента TFTP

================================================================================================================================== ============

int sockfd; 
struct sockaddr_in serv_addr; 


//called when we retrieve a file from the server 
void getFile(int port, char *filename) 
{ 
    printf("enter to get file\n"); 
    FILE * file; 

    if (strchr(filename,'/') != NULL) 
    { 
     printf("We do not support file transfer out of the current working directory\n"); 
     return; 
    } 

    file = fopen(filename, "wb"); 

    if(file == NULL) 
    { 
     perror(filename); 
     return; 
    } 

    if(sockfd < 0) 
    { 
     printf("Couldn't open socket\n"); 
     return; 
    } 

    if(!send_RRQ(sockfd, (struct sockaddr *) &serv_addr, filename, TFTP_SUPORTED_MODE)) 
    { 
     printf("Error: couldn't send RRQ\n"); 
     return; 
    } 
    if(!recvFile(sockfd, (struct sockaddr *) &serv_addr, file,filename)) 
    { 
     printf("Error: didn't receive file\n"); 
     return; 
    } 
    fclose(file); 
    return; 
} 


//used to upload files to the server 
void putFile(int port, char *filename) 
{ 
    printf("filenemae is: %s \t",filename); 

    PACKET packet; 
    int result; 
    FILE * fileh; 
    int timeout_counter = 0; 

    if (strchr(filename,'/') != NULL) 
    { 
     printf("We do not support file transfer out of the current working directory\n"); 
     return; 
    } 


    fileh = fopen(filename, "rb"); 

    if(fileh == NULL) 
    { 
     perror(filename); 
     return; 
    } 

    if(!send_WRQ(sockfd, (struct sockaddr *) &serv_addr, filename, TFTP_SUPORTED_MODE)) 
    { 
     printf("Error: couldn't send WRQ to server\n"); 
     return; 
    } 

    while (timeout_counter < MAX_TFTP_TIMEOUTS) 
    { 
     result = waitForPacket(sockfd, (struct sockaddr *) &serv_addr, TFTP_OPTCODE_ACK, &packet); 
     if (result < 0) 
     { 
      printf("Error: Timeout sending packet to server\n"); 
      if(!send_WRQ(sockfd, (struct sockaddr *) &serv_addr, filename, TFTP_SUPORTED_MODE)) 
      { 
       printf("Error: couldn't send WRQ to server\n"); 
       return; 
      } 
      timeout_counter++; 
     }else 
     { 
      break; 
     } 
    } 
    if (result < 0) 
    { 
     //we still timed out 
     printf("Timed out after %d tries, is the server running\n",MAX_TFTP_TIMEOUTS); 
     fclose(fileh); 
     return; 
    } 
    if (packet.optcode == TFTP_OPTCODE_ERR) 
    { 
     //we recieved an error, print it 
     printError(&packet); 
    }else 
    { 
     if (!sendFile(sockfd, (struct sockaddr *) &serv_addr, fileh)) 
     { 
      printf("Unable to send file to server\n"); 
     } 
    } 
    fclose(fileh); 
    return; 
} 

int createUDPSocketAndBind(int port) 
{ 
    //create a socket 
    sockfd = socket(PF_INET, SOCK_DGRAM, 0); 

    //return -1 on error 
    if (sockfd == -1) 
    { 
    return -1; 
    } 

    //zero out the struct 
    bzero((char*) &serv_addr, sizeof(serv_addr)); 

    serv_addr.sin_family = AF_INET; 
    serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); 
    serv_addr.sin_port = htons(port); 

    return 0; 
} 


//main client, checks for args and starts an operation if no errors detected 
int main(int argc, char *argv[]) 
{ 
    int port = 59; 
    int argOffset = 1; 
    char* filename; 
    char fme[] = "test.txt"; 

    createUDPSocketAndBind(port); 

    printf("for put file\n"); 
    putFile(port,fme); //=====> this operation is successful. 


    //createUDPSocketAndBind(port); //=====> If I uncomment this function, next operation works. 

    printf("for getfile\n"); 
    getFile(port,fme); //=======> It is failing. 

    printf("Usage: %s [-p port] (-w putfile || -r getFile)\n",argv[0]); 
} 

========================================================================= 

ответ

0

Я исследовал еще и нашел проблему с моим кодом и решением.

Когда вы отправляете первый запрос RD/WR на сервер, он создаст отдельный процесс или поток для обработки вашего запроса и в то же время создаст новый сокет и будет использовать другой номер порта для обработки запрос RD/WR.

Клиентская сторона, когда вы получите ответ от сервера, используя нижеприведенный API сокетов UDP.

ssize_t recvfrom (int sockfd, void * buf, size_t len, int flags, struct sockaddr * src_addr, socklen_t * addrlen);

В списке портов экземпляра «struct sockaddr * src_addr» будет обновляться по мере ответа сервера с использованием другого номера порта, который для обработки вашего запроса был создан сервер , и ваша операция RD/WR завершится успешно, используя этот номер порта.

Как только RD/WR будет успешно завершен, сервер закроет сокет, который был создан для обработки запроса и начнет прослушивать ваш новый запрос на оригинальном порту. Но экземпляр «struct sockaddr * src_addr» на стороне клиента по-прежнему будет иметь измененный номер порта, и когда вы попытаетесь отправить новый запрос RD/WR, он не дойдет до сервера. И в этом причина того, что второй запрос RD/WR не дойдет до сервера, и он потерпит неудачу.

Чтобы исправить это на стороне клиента в экземпляре «struct sockaddr * src_addr», вам необходимо сбросить порт до начального значения, которое вы первоначально использовали для настройки экземпляра сервера «struct sockaddr * src_addr». Поэтому после каждой операции RD/WR вы должны сбросить номер порта до первоначального значения.

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

С благодарностью

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