之前项目中有个地方要实现一个功能,就是通过非终端串口传输文件,这里将其作为一个小功能模块,简单的介绍一下自己是如何实现的!SecureCRT超级终端上可以通过lrz等工具通过命令传输文件这个就不介绍,之前的博客也有写过怎么编译移植使用这个工具,这次是自己来编码实现通过非终端调试串口来安全可靠的传输任何文件。
其实刚开始想的时候觉得有一点难度,一是要自己定协议,如何定协议才合理呢?二是当时自己也想的有点复杂,一个文件所包含的文件信息又有哪些呢?通过串口传输过来的数据又需要怎样的及时的写入文件呢?传输文件又用到什么校验算法呢?反正一开始自己脑子里就是一大堆的问题!想出问题来了就好说了!既然是C语言,还是自己定协议,那当然就是一步一步的来了!
我们这个要结合上位机软件,上位机软件是别人写的!憋屈自己不会上位机,文件校验用的是SHA1校验算法,博客里面也有!
首先项目需求是我们要传输的文件大小不会很大,大到天也不会超过5M,协议我自己是这样定的:
------------------------------------------------------------------------------------------------------------------------
10字节,传输的字节总长度 | 255字节 文件名 | 20字节的SHA1校验码(直接)
-------------------------------------------------------------------------------------------------------------------------
对于一个文件的关键信息,就是文件名,文件数据长度!有了这两个关键信息,这样就可以在Linux下通过C应用编程实现还原传输过来的文件!
整个过程分为两次数据包传送:
第一个数据包为固定长度 285字节,传输的字节数还有文件名上位机都是以字符串的形式(也就是ASC形式)传输过来的,后面20字节是直接传输,不用转化!字节数和文件名长度不够的地方都是以空格填充!
第二个数据包是直接传输文件里面的数据,把文件里面的数据原封不动的传输过来,同时下位机这边接收数据,malloc出一片内存来暂时存放临时数据,文件数据传输完毕后,计算20字节SHA1校验码,把生成的校验码与上位机传输过来的校验码对比,如果完全一致,表示传输成功!
串口read数据是用非阻塞的方式!这里第一个数据包传输完后会向上位机返回一个确认信号!这个也是完全自定义!
这里简单的贴上下位机部分处理的代码!上位机COM测试程序我这里没有源码,只有一个应用程序,传上来也没什么大用!当然这里处理部分的代码只能作为参考!前期写的还是比较粗糙!(这个是测试部分的代码)
- static void chmodfile777(void)
- {
- int status = 0;
-
- status = system("./Appupdate.sh");
-
- if(-1 == status)
- {
- printf("system error!");
- }
- else
- {
- printf("exit status value = [0x%x]\n", status);
- }
-
- }
-
-
- struct file_inode
- {
- int filesize;
- char filename[256];
- char shal[21];
-
- }fileinfo;
-
-
- ------------------------------------------------------------------
- 10字节,传输的字节总长度| 255字节 文件名 | 20字节的SHA1校验码
- ------------------------------------------------------------------
-
- void Cmd_Func_IAP(char (*p)[ONEMSGLENTH])
- {
- int len;
- int wlen;
- static int nreadsize = 0;
- int itemfd = -1;
-
- char temp[10] = {'\0'};
- char tmp0[300] = {'\0'};
- char str[25] = {'\0'};
-
- SHA1Context sha;
- int i, err;
- uint8_t Message_Digest[20];
-
- char *Pstrcache = NULL;
- int equal = 0;
- int fnamesize = 0;
-
- nreadsize = 0;
-
- while(nreadsize < 285)
- {
-
- len = read(fd, temp, 8);
-
-
- if(len > 0)
- nreadsize += len;
-
- temp[len] = '\0';
-
- strcat(tmp0,temp);
- bzero(temp,10);
-
- }
-
-
-
-
- tmp0[285] = '\0';
-
-
-
- strncpy(str,tmp0,10);
- str[10] = '\0';
- fileinfo.filesize = atoi(str);
-
- strncpy(&(fileinfo.filename[0]), &(tmp0[10]), 255);
- strncpy(&(fileinfo.shal[0]), &(tmp0[265]), 20);
-
- fileinfo.filename[255] = '\0';
-
-
-
-
-
-
-
- while(fileinfo.filename[fnamesize] != 32)
- {
- fnamesize++;
- }
-
- memset(tmp0, '\0' ,300);
- strncpy(tmp0,"/opt/START/", strlen("/opt/START/"));
-
- tmp0[strlen("/opt/START/")] = '\0';
- fileinfo.filename[fnamesize] = '\0';
-
- strcat(tmp0, fileinfo.filename);
-
-
- itemfd = open(tmp0, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
-
- if(itemfd != -1)
- {
- fileinfo.filesize = fileinfo.filesize - 285;
-
- Pstrcache = (char *)malloc( sizeof(char)*(fileinfo.filesize) );
- nreadsize = 0;
- len = 0;
- if(Pstrcache != NULL)
- {
-
- while(nreadsize < fileinfo.filesize )
- {
- len = read(fd, &(Pstrcache[nreadsize]),fileinfo.filesize);
-
- if(len > 0)
- nreadsize += len;
-
- len = 0;
- }
- }
-
-
- err = SHA1Reset(&sha);
- err = SHA1Input(&sha,(const unsigned char *) Pstrcache,fileinfo.filesize);
- err = SHA1Result(&sha, Message_Digest);
-
- for(i = 0; i < 20 ; ++i)
- {
-
-
- if( Message_Digest[i] != fileinfo.shal[i] )
- {
- printf("recevice fail!\n");
- len = write(fd, "update fail!\n",sizeof("update fail!\n") );
- equal = 1;
-
- }
-
- }
-
-
- if(equal != 1)
- {
- wlen = write(itemfd, Pstrcache, fileinfo.filesize);
-
- len = write(fd, "update succeed!\n",sizeof("update succeed!\n") );
-
- chmodfile777();
- }
-
- }
-
- free(Pstrcache);
- Pstrcache = NULL;
-
- }
反正测试代码当初配合上位机测试的时候是没有任何问题的,二进制文件、*.txt、.c等文件格式都能成功通过串口传输过来。其实做出来的过程也是相当的简单,这个在百度上很少看到有相关的讲解,如何用C实现通过串口传输文件!这个也是完全从想到做到实现的一个过程!发现其实真的很简单!关于SHA1校验这个博客里面源码有介绍!