2017-01-10 21 views
0

实现了UDP套接字TFTP客户端。 首先,我创建UDP非阻塞套接字和执行PUT/GET操作它工作正常。 但是,当我再次尝试执行GET/PUT它不起作用。 RRQ/WRQ请求本身没有到达服务器,而是从客户端发送成功。 以下是我的tftp客户端代码。第二次TFTP PUT opearation不工作成功完成第一次在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请求。

客户端时,您将收到来自以下使用UDP套接字API服务器的响应。 (int sockfd,void * buf,size_t len,int标志, struct sockaddr * src_addr,socklen_t * addrlen);

在“结构sockaddr * SRC_ADDR”实例端口号会服务使用的服务器 创造来处理您的请求,您的RD/WR操作将成功完成使用此端口号不同的端口号响应进行更新。

一旦RD/WR成功完成,服务器将关闭已创建的套接字以处理您的请求,并开始在原始端口上收听您的新请求 。但是,客户端“结构sockaddr * SRC_ADDR”实例还会有修改端口号,当您尝试发送新的RD/WR请求不会到达服务器。这就是第二次RD/WR请求不会到达服务器的原因,并且会失败。

要在“struct sockaddr * src_addr”实例的客户端修复此问题,您必须将端口重置为最初用于配置“struct sockaddr * src_addr”的服务器实例的初始值。因此,在每次RD/WR操作之后,您必须将端口号 重置为原始值。

我很新的UDP套接字,这是很好的学习对我来说。 我认为这会对像我这样的初学者有帮助。

谢谢

相关问题