linux 通过tcp远程传输文件例子

最近客户要拿几块板子到现场环境跑测试,而这套软件也需要根据实际情况作修改,而且客户也要不断增加功能。于是写了一套远程升级软件,因为只是调试时使用,所以不会有报文CRC校验之类的功能。

升级流程由服务器端发起,客户端负责把文件保存到指定目录下。重启后会自动升级。这里把整个流程分为几个状态,并且把当前状态放进报文里,接收方根据报文里的状态值分析报文内容。状态及流程如下:

停止状态

开始状态             

主      ->           启动升级报文(0x01)

                                                                回复报文(0x01)       <-      从

传输状态

主      ->           传输报文(0x02)   流水号    长度(H)    长度(L)     报文内容

                                                                回复报文(0x02)    流水号       <-      从 

结束状态

主        ->        0x03

                                                                       0x03              <-         从

 

下面直接贴代码,服务器端:

/* 升级状态定义 */
#define UPGRADE_STOP        (0)
#define UPGRADE_START       (1)
#define UPGRADE_TRANSMIT    (2)
#define UPGRADE_FINISH      (3)

/* 升级相关结构体 */
struct upgrade_ctrl_s{
    char file_name[256];       /* 用于升级的文件名 */
    int fd;
    off_t file_size;
    unsigned int hub_id;
    unsigned int send_cnt;
    unsigned char frame_id;    /* 流水号 */
};

struct upgrade_ctrl_s g_upgrade_ctrl;

// 结构体初始化
void upgrade_init(void)
{
    memset(&g_upgrade_ctrl, 0, sizeof(g_upgrade_ctrl));
}

// 启动升级流程
int upgrade_start(int sfd, int hub_id)
{
    struct stat file_stat;
    unsigned char buf_send[2048] = {0};

    g_upgrade_ctrl.fd = open("file name", O_RDONLY);
    if ( g_upgrade_ctrl.fd < 0 )
    {
        printf("error: can not open file: %s\r\n", "file name");
        return 0;
    }

    if ( stat("file name", &file_stat) < 0 )
    {
        close(g_upgrade_ctrl.fd);
        return 0;
    }

    g_upgrade_ctrl.file_size = file_stat.st_size;
    g_upgrade_ctrl.hub_id = hub_id;
    g_upgrade_ctrl.frame_id = 0;
    g_upgrade_ctrl.send_cnt = 0;

    /* 发启动报文 */
    buf_send[0] = PROT_FLAG_SERVER;
    buf_send[1] = PROT_METER_UPGRADE;
    buf_send[2] = UPGRADE_START;
    buf_send[3] = PROT_FLAG_SERVER;
    (void)send(sfd, buf_send, 4, 0);

    return 1;
}

// 文件数据传输
int upgrade_send(int sfd)
{
    unsigned char buf_send[2048] = {0};
    int ret;

    g_upgrade_ctrl.frame_id++;
    buf_send[0] = PROT_FLAG_SERVER;
    buf_send[1] = PROT_METER_UPGRADE;
    buf_send[2] = UPGRADE_TRANSMIT;
    buf_send[3] = g_upgrade_ctrl.frame_id;

    ret = read(g_upgrade_ctrl.fd, &buf_send[6], 1000); /* 每次发1000字节 */
    if ( ret <= 0 )
        return ret;

    g_upgrade_ctrl.send_cnt += ret;

    buf_send[4] = (unsigned char)(ret >> 8);
    buf_send[5] = (unsigned char)ret;
    ret += 6;
    buf_send[ret] = PROT_FLAG_SERVER;
    ret++;

    (void)send(sfd, buf_send, ret, 0);

    return ret;
}

void upgrade_send_error(int sfd)
{
    unsigned char buf_send[4];

    /* 发因为错误而结束报文 */
    buf_send[0] = PROT_FLAG_SERVER;
    buf_send[1] = PROT_METER_UPGRADE;
    buf_send[2] = UPGRADE_STOP;
    buf_send[3] = PROT_FLAG_SERVER;
    (void)send(sfd, buf_send, 4, 0);
}


//  处理中继升级相关报文
void svr_meter_upgrade(int sfd, unsigned char *buff, unsigned int len)
{
    unsigned char buf_send[2048] = {0};

    if ( buff[2] == UPGRADE_START )
    {/* 起始协议 */
        if ( buff[3] == 1 )
        {
            if ( upgrade_send(sfd) > 0 )
            {
                return;
            }
            else
            {
                /* 发启动报文 */
                buf_send[0] = PROT_FLAG_SERVER;
                buf_send[1] = PROT_METER_UPGRADE;
                buf_send[2] = UPGRADE_START;
                buf_send[3] = PROT_FLAG_SERVER;
                (void)send(sfd, buf_send, 4, 0);
            }
        }
        else
        {
            memset(&g_upgrade_ctrl, 0, sizeof(g_upgrade_ctrl));
        }
    }
    else if ( buff[2] == UPGRADE_TRANSMIT )
    {
        if ( buff[3] != g_upgrade_ctrl.frame_id )
        {
             /* 传输出错,等待重新再来 */
             close(g_upgrade_ctrl.fd);
             memset(&g_upgrade_ctrl, 0, sizeof(g_upgrade_ctrl));
             upgrade_send_error(sfd);
        }
        else
        {
            if ( g_upgrade_ctrl.send_cnt == g_upgrade_ctrl.file_size )
            {// 传输完成

                memset(&g_upgrade_ctrl, 0, sizeof(g_upgrade_ctrl));

                buf_send[0] = PROT_FLAG_SERVER;
                buf_send[1] = PROT_METER_UPGRADE;
                buf_send[2] = UPGRADE_FINISH;
                buf_send[3] = PROT_FLAG_SERVER;
                (void)send(sfd, buf_send, 4, 0);
            }
            else
            {
                upgrade_send(sfd);
            }
        }
    }
}

客户端:


/* 升级状态定义 */
#define UPGRADE_STOP        (0)
#define UPGRADE_START       (1)
#define UPGRADE_TRANSMIT    (2)
#define UPGRADE_FINISH      (3)

#define UPGRADE_FILE_NAME "/data/upgrade.tar.gz"

/* 升级相关结构体 */
struct upgrade_ctrl_s{
    int fd;                    /* 保存文件句柄 */
    unsigned char frame_id;    /* 流水号 */
    unsigned int timeout_cnt;  /* 超过一定时间没升级交互就退出升级流程 */
};

struct upgrade_ctrl_s g_upgrade_ctrl;

void prot_meter_upgrade_handle(unsigned char *buf, unsigned int len)
{
    unsigned char buf_send[2048] = {0};
    unsigned int data_len;

    if ( buf[1] == UPGRADE_STOP )
    {// 服务器端主动停止升级流程
        if ( g_upgrade_ctrl.fd > 0 ) 
            close(g_upgrade_ctrl.fd);

        memset(&g_upgrade_ctrl, 0, sizeof(g_upgrade_ctrl));
    }
    else if ( buf[1] == UPGRADE_START )
    {/* 开始升级 */
        if ( g_upgrade_ctrl.fd > 0 ) 
            close(g_upgrade_ctrl.fd);

        memset(&g_upgrade_ctrl, 0, sizeof(g_upgrade_ctrl));
        g_upgrade_ctrl.fd = open(UPGRADE_FILE_NAME, O_RDWR|O_CREAT|O_TRUNC);
        if ( g_upgrade_ctrl.fd >= 0 )
        {
            g_upgrade_ctrl.frame_id = 1;
            g_upgrade_ctrl.timeout_cnt = 3;
            buf_send[3] = 1;
        }
        else
        {
            buf_send[3] = 0;
        }

        buf_send[0] = PROT_FLAG_TX;
        buf_send[1] = PROT_METER_UPGRADE;
        buf_send[2] = UPGRADE_START;
        buf_send[4] = PROT_FLAG_TX;
        tcp_client_send(buf_send, 5);
    }
    else if ( buf[1] == UPGRADE_TRANSMIT )
    {
        if ( g_upgrade_ctrl.frame_id != buf[2] )
        {/* 流水号不一致,出错 */
            if ( g_upgrade_ctrl.fd > 0 ) 
                close(g_upgrade_ctrl.fd);

            memset(&g_upgrade_ctrl, 0, sizeof(g_upgrade_ctrl));

            buf_send[0] = PROT_FLAG_TX;
            buf_send[1] = PROT_METER_UPGRADE;
            buf_send[2] = UPGRADE_TRANSMIT;
            buf_send[3] = buf[2] + 100; /* 与接收的流水号不一致,服务端就知道出错了 */
            buf_send[4] = PROT_FLAG_TX;
            tcp_client_send(buf_send, 5);
            return;
        }
        else
        {
            data_len = buf[3];
            data_len <<= 8;
            data_len |= buf[4];
            write(g_upgrade_ctrl.fd, &buf[5], data_len);

            buf_send[0] = PROT_FLAG_TX;
            buf_send[1] = PROT_METER_UPGRADE;
            buf_send[2] = 2;
            buf_send[3] = buf[2];
            buf_send[4] = PROT_FLAG_TX;
            tcp_client_send(buf_send, 5);

            g_upgrade_ctrl.timeout_cnt = 3;
            g_upgrade_ctrl.frame_id++;

            return;
        }
    }
    else if ( buf[1] == UPGRADE_FINISH ) 
    {// 传输完成
        if ( g_upgrade_ctrl.fd > 0 ) 
                close(g_upgrade_ctrl.fd);

        sleep(1);

        memset(&g_upgrade_ctrl, 0, sizeof(g_upgrade_ctrl));
    }
}

int upgrade_is_busy(void)
{
    if ( g_upgrade_ctrl.timeout_cnt > 0 )
    {
        g_upgrade_ctrl.timeout_cnt--;
        if ( g_upgrade_ctrl.timeout_cnt == 0 ) 
        {// timeout
            if ( g_upgrade_ctrl.fd > 0 ) 
                close(g_upgrade_ctrl.fd);

            memset(&g_upgrade_ctrl, 0, sizeof(g_upgrade_ctrl));
        }
    }

    return g_upgrade_ctrl.timeout_cnt;
}

 

end

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值