第二次TFTP PUT操作在TFTP客户端第一次成功完成GET / PUT操作后不起作用

时间:2017-01-10 13:42:25

标签: linux udp tftp

通过UDP套接字实现TFTP客户端。 首先,我创建UDP非阻塞套接字并执行PUT / GET操作,它工作正常。 但是当我再次尝试执行GET / PUT时它不起作用。 RRQ / WRQ请求本身未到达服务器,但是从客户端到达它已成功发送。 下面是我的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]);
}

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

1 个答案:

答案 0 :(得分:0)

我已经进行了更多调查,并发现了我的代码和解决方案的问题。

当您向服务器发送第一个RD / WR请求时,它将创建一个单独的进程或线程来处理您的请求,同时它将创建新的套接字并将使用不同的端口号来处理RD / WR请求。

客户端,当您使用以下UDP套接字API从服务器收到响应时。

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套接字很新,对我来说这很好。 我认为这对像我这样的初学者会有所帮助。

由于