Chinaunix首页 | 论坛 | 博客
  • 博客访问: 524353
  • 博文数量: 87
  • 博客积分: 4086
  • 博客等级: 上校
  • 技术积分: 900
  • 用 户 组: 普通用户
  • 注册时间: 2007-12-23 15:55
文章分类

全部博文(87)

文章存档

2012年(3)

2010年(13)

2009年(7)

2008年(64)

我的朋友

分类: LINUX

2010-12-18 17:28:12

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

/*************************************************
 * 这个程序实现了TFTP客户端,在Linux上编译通过并 *
 * 正常使用。使用socket编程,具体的TFTP协议由于 *
 * 篇幅太长,这里没有列出来,可以参考网址:         *
 * *
 ************************************************/

#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 \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;
}


阅读(8803) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~