您的位置:首页 > 运维架构 > Linux

linux下tftp server的一种简易实现

2012-09-22 14:33 176 查看
转自:http://blog.chinaunix.net/uid-11911430-id-2801536.html

博主:经测试,能够使用

最近学习LINUX socket编程,利用socket实现了一个Linux下命令行的tftp客户端,此客户端只可以从TFTP服务器获取文件。使用格式为:./tftpget <ipaddr> <filename>。该程序可以运行在Linux的PC机上,也可以运行在嵌入式开发板上(需交叉编译)。程序的源代码及其注释如下:



/************************************************* 

 * 这个程序实现了TFTP客户端,在Linux上编译通过并 *

 * 正常使用。使用socket编程,具体的TFTP协议由于 *

 * 篇幅太长,这里没有列出来,可以参考网址:         *

 * http://www.faqs.org/rfcs/rfc1350.html         *

 ************************************************/ 

#include <stdio.h>

#include <sys/socket.h>

#include <sys/types.h>

#include <netdb.h>

#include <string.h>

//下面定义的几个宏是TFTP协议的操作码,参考协议

#define OP_RRQ        1 //读请求

#define OP_WRQ        2 //写请求

#define OP_DATA        3 //数据包

#define OP_ACK        4 //确认包

#define OP_ERROR    5 //错误信息

//TFTP错误信息编码

static char *error_string[] = {

    "Not defined error!",                    //0

    "File not found!",                        //1

    "Access denied!",                        //2

    "Disk full or allocation exceeded!",    //3

    "Illegal TFTP operation!",                //4

    "Unknown transfer ID!",                    //5

    "File already exists!",                    //6

    "No such user!"                            //7

};

int main(int argc, char **argv)

{

    int socketFD; //socket描述符

    struct sockaddr_in tftpServer, tftpClient; //自身和服务器的socket信息

    FILE *fp; //用于保存本地文件

    char buffer[516]; //网络通信用的buffer

    int addrlen;

    int lastPacket, currentPacket; //包计数

    unsigned short *s_ptr; 

    char *c_ptr;

    int tmp;

    int ret;

    if (argc < 3)

    {

        //使用方式

        printf("Usage: %s <ipaddr> <filename>\n", argv[0]);

        return 0;

    }

    //创建socket

    socketFD = socket(AF_INET, SOCK_DGRAM, 0);

    if (-1 == socketFD)

    {

        printf("Can not create socket!\n");

        return 0;

    }

    //客户端自身信息

    bzero(&tftpClient, sizeof (tftpClient));

    tftpClient.sin_family = AF_INET;

    tftpClient.sin_addr.s_addr = INADDR_ANY;

    tftpClient.sin_port = htons(0);

    //绑定socket到本机IP地址

    tmp = bind(socketFD, (struct sockaddr *)&tftpClient, sizeof (tftpClient));

    if (0 != tmp)

    {

        printf("Can not bind socket!\n");

        goto error_1;

    }

    //服务器信息

    bzero(&tftpServer, sizeof (tftpServer));

    addrlen = sizeof (tftpServer);

    tftpServer.sin_family = AF_INET;

    tftpServer.sin_addr.s_addr = inet_addr(argv[1]);

    tftpServer.sin_port = htons(69); //TFTP服务端口

    s_ptr = (unsigned short *)&buffer[0];

    *s_ptr = htons(OP_RRQ); //操作码

    c_ptr = &buffer[2]; 

    strcpy(&buffer[2], argv[2]); //远程文件名

    c_ptr += strlen(argv[2]);

    *c_ptr++ = 0;

    strcpy(c_ptr, "netascii"); //模式

    c_ptr += 8;

    *c_ptr++ = 0;

    //创建一个本地文件

    fp = fopen(argv[2], "w");

    if (NULL == fp)

    {

        printf("Can not create locale file!\n");

        goto error_1;

    }

    lastPacket = 0;

    while (1)

    {

        //发送请求或者回应包到服务器

        tmp = sendto(socketFD, buffer, c_ptr - &buffer[0], 0, 

                    (struct sockaddr *)&tftpServer, sizeof (tftpServer));

        if (-1 == tmp)

        {

            printf("Can not send buffer!\n");

            goto error_2;

            return 0;

        }

        //从服务器获取数据包

        tmp = recvfrom(socketFD, buffer, 516, 0, (struct sockaddr *)&tftpServer,&addrlen);

        if (-1 == tmp)

        {

            printf("Receive data error!\n");

            goto error_2;

            return 0;

        }

        else

        {

            switch (ntohs(*s_ptr))

            {

                //数据包

                case OP_DATA:

                    currentPacket = ntohs(*(s_ptr+1));

                    //验证包的顺序

                    if ((lastPacket + 1) != currentPacket)

                    {

                        printf("ERROR: packet error!\n");

                        goto error_2;

                    }

                    lastPacket = currentPacket;

                    tmp -= 4;

                    //写入数据到本地文件

                    ret = fwrite(&buffer[4], 1, tmp, fp);

                    if (tmp != ret)

                    {

                        printf("ERROR: write to
 local file error!\n");

                        goto error_2;

                    }

                    //如果等于512则不是最后一个包

                    if (512 != tmp)

                    {

                        goto read_ok;

                    }

                    //准备返回信息

                    *s_ptr = htons(OP_ACK);

                    *(s_ptr + 1) = htons(currentPacket);

                    c_ptr = &buffer[4];

                    break;

                //服务器返回错误信息

                case OP_ERROR:

                    //根据错误码,打印错误信息

                    printf("ERROR: %s\n", error_string[ntohs(*(s_ptr+1))]);

                    goto error_2;

                    break;

                //发生其他未知错误

                default:

                    printf("ERROR: Unknow error!\n");

                    goto error_2;

                    break;

            }

        }

    }

read_ok:

    fclose(fp);

    close(socketFD);

    return 0;

error_2:

    fclose(fp);

    unlink(argv[2]);

error_1:

    close(socketFD);

    

    return 0;

}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: