背景:设备端(采集端) + 云端(服务端)+ 浏览端(客户端)这种结构是比较常见的,而在某些情形,云端如果涉及到跨境跨域的问题,上述的架构就不一定合适。在功能要求不是那么复杂的情况下,可以考虑设备端(采集端+服务端)+ 浏览端(客户端)这种架构。在设备端移植搭建服务器,并将显示的相关html文件部署其上,浏览器输入设备地址及html文件名,即可实现远程监控功能。
功能:点击网页上文件选择按钮,从本地选择待上传的文件,完成后点击上传按钮,将选中的文件上传到web server。
HTML内容如下
例子一:
- html>
- <html>
- <head>
- <title>文件上传title>
- head>
- <body>
- <form action="/cgi-bin/upload.cgi" enctype="multipart/form-data" method="post">
- <table>
- <tbody>
- <tr>
- <td> upload file td>
- <td><input type="file" name="uploadfile" value="">td>
- <td><input type="submit" name="upload" value="上传">td>
- tr>
- tbody>
- table>
- form>
- body>
- html>
例子二(网友方案):
- html>
- <html>
- <style>
- body
- {
- background-color: lightblue;
- }
- div
- {
- margin-left: 30px;
- margin-top: 30px;
- }
- style>
- <head>
- <meta charset="utf-8">
- <title>Upload File Testtitle>
- head>
-
- <body>
- <form enctype='multipart/form-data' action="/cgi-bin/upload.cgi" method="post">
- <div>
- <span>上传路径:span><input type="text" name="updatapath" value="/tmp/">
- div>
- <div>
- <input type="file" name='updatafile' multiple>
- div>
- <div>
- <input type="submit" value="确认上传">
- div>
-
- body>
- html>
上传文件功能必须开启
enctype="multipart/form-data" method="post"
CGI C实现:
例子一配套C代码:
- #include
- #include
- #include
- #include "cgic.h"
-
- enum ErrLog
- {
- ErrSucceed,
- ErrOpenFile,
- ErrNoFile
- };
- enum ErrLog UploadFile()
- {
- cgiFilePtr file;
- FILE *fd;
- char name[512];
- char path[128];
- char contentType[1024];
- int size = 0;
- int got = 0;
- int t = 0;
- char *tmp = NULL;
-
- cgiHeaderContentType("text/html; charset=utf-8");
-
- cgiFormResultType ret;
- ret = cgiFormFileName("uploadfile", name, sizeof(name));
- switch(ret)
- {
- case cgiFormNotFound:
- printf("
cgiFormNotFound.
\n"); - break;
- case cgiFormTruncated:
- printf("
cgiFormTruncated.
\n"); - break;
- case cgiFormSuccess:
- printf("
cgiFormSuccess.
\n"); - break;
- default:
- printf("
unknown.
\n"); - break;
- }
- if (ret != cgiFormSuccess) //获取客户端pathname
- {
- printf("
%s No file was uploaded.
\n", name); - return ErrNoFile;
- }
- fprintf(cgiOut, "The filename submitted was: ");
- cgiHtmlEscape(name);
- fprintf(cgiOut, "
\n"); -
- cgiFormFileSize("uploadfile", &size);
- fprintf(cgiOut, "The file size was: %d bytes
\n", size); -
- cgiFormFileContentType("uploadfile", contentType, sizeof(contentType));
- fprintf(cgiOut, "The alleged content type of the file was: ");
- cgiHtmlEscape(contentType);
- fprintf(cgiOut, "
\n"); -
- if (cgiFormFileOpen("uploadfile", &file) != cgiFormSuccess) //尝试打开上传的,并存放在系统中的临时文件
- {
- fprintf(cgiOut, "
Could not open the file.
\n"); - return ErrOpenFile;
- }
-
- t = -1;
- while (1)
- {
- tmp = strstr(name+t+1, "\\"); // 从pathname解析出filename
- if (NULL == tmp)
- {
- tmp = strstr(name+t+1, "/");
- }
- if (NULL != tmp)
- {
- t = (int)(tmp-name);
- }
- else
- {
- break;
- }
- }
- tmp = (char *)malloc(size * sizeof(char)); // 在底层建立新文件
- strcpy(path, "/tmp/"); // 路径最后一个字符必须是'/',否则最终的文件(带路径)将会不知道写到什么地方去了
- strcat(path, name+t+1);
- fd = fopen(path, "wb");
- if (fd == NULL)
- {
- return ErrOpenFile;
- }
-
- while (cgiFormFileRead(file, tmp, size, &got) == cgiFormSuccess) // 从临时文件读出content
- {
- fwrite(tmp, size, sizeof(char), fd); //把读出的content写入新文件
- }
- fprintf(cgiOut, "
Upload File Success.
\n"); -
- cgiFormFileClose(file);
- free(tmp);
- fclose(fd);
- return ErrSucceed;
- }
-
- int cgiMain()
- {
- return UploadFile();
-
- }
例子二配套C代码(网友方案,借鉴于CGI提供的cgitest.c例子,里面涉及到CGI的各种特性):
- /* Change this if the SERVER_NAME environment variable does not report
- the true name of your web server. */
- #if 1
- #define SERVER_NAME cgiServerName
- #endif
- #if 0
- #define SERVER_NAME "www.boutell.dev"
- #endif
-
- /* You may need to change this, particularly under Windows;
- it is a reasonable guess as to an acceptable place to
- store a saved environment in order to test that feature.
- If that feature is not important to you, you needn't
- concern yourself with this. */
-
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include "cgic.h"
-
- //#define DEBUG_ON
- #ifdef DEBUG_ON
- void PrintMessage(const char *str)
- {
- int fd;
- fd = open("/home/vmuser/mycgi_log",O_WRONLY|O_CREAT|O_APPEND);
- if(fd < 0)
- return;
-
- time_t the_time;
-
- struct tm *info;
- time(&the_time);
- info = gmtime(&the_time );
-
- dprintf(fd,"[%2d:%02d]\n", (info->tm_hour)%24, info->tm_min);
-
- write(fd,str,strlen(str));
-
- close(fd);
-
- }
- #endif
-
-
- enum ErrLog
- {
- ErrSucceed = 0x00,
- ErrOpenFile,
- ErrNoFile,
- ErrNonePath
- };
-
- int cgiMain() {
-
- cgiFilePtr file;
- FILE *fd;
- char name[512];
- char path[128];
- char contentType[1024];
- int size = 0;
- int got = 0;
- int t = 0;
- char *tmp = NULL;
-
- //设置类型文件
- cgiHeaderContentType("text/html; charset=utf-8");
- if (cgiFormFileName("updatafile", name, sizeof(name)) != cgiFormSuccess) //获取客户端pathname
- {
- fprintf(cgiOut,"
文件上传失败.
\n"); - return ErrNoFile;
- }
-
- //显示上传文件内容
- fprintf(cgiOut, "提交上传文件名称: ");
- cgiHtmlEscape(name);//虽然已经获取到名称,如果文件名中有特殊的名称,将会被转换,总结:从html获取的字符串需要显示到网页的用这个比较好,用fprintf也可以。
- fprintf(cgiOut, "
\n"); -
- //获取文件大小
- cgiFormFileSize("updatafile", &size);
- fprintf(cgiOut, "文件大小为: %d 字节
\n", size); -
- //上传文件内容类型
- cgiFormFileContentType("updatafile", contentType, sizeof(contentType));
- fprintf(cgiOut, "文件的内容类型为: ");
- cgiHtmlEscape(contentType);
- fprintf(cgiOut, "
\n"); -
- if (cgiFormString("updatapath", path, sizeof (path)) != cgiFormSuccess)
- {
- fprintf(cgiOut, "
Could not open the file.
\n"); - return ErrNonePath;
- }
-
- //上传文件内容类型
- fprintf(cgiOut, "文件的路径: ");
- cgiHtmlEscape(path);
- fprintf(cgiOut, "
\n"); -
- //尝试打开上传的,并存放在系统中的临时文件
- if (cgiFormFileOpen("updatafile", &file) != cgiFormSuccess)
- {
- fprintf(cgiOut, "
Could not open the file.
\n"); - return ErrOpenFile;
- }
-
- t = -1;
- while (1)
- {
- tmp = strstr(name+t+1, "\\"); // 从pathname解析出filename
- if (NULL == tmp)
- tmp = strstr(name+t+1, "/");
- if (NULL != tmp)
- t = (int)(tmp-name);
- else
- break;
- }
- //动态内存分配
- tmp = (char *)malloc(size * sizeof(char));
- strcat(path, name+t+1);
-
- //上传文件内容类型
- fprintf(cgiOut, "最终生成文件: ");
- cgiHtmlEscape(path);
- fprintf(cgiOut, "
\n"); -
-
- //创建文件,以字节流的方式打开
- fd = fopen(path, "wb+");
- if (fd == NULL)
- {
- return ErrOpenFile;
- }
-
- // 从临时文件读出content
- while (cgiFormFileRead(file, tmp, size, &got) == cgiFormSuccess)
- {
- fwrite(tmp, size, sizeof(char), fd); //把读出的content写入新文件
- }
-
- //打印输出
- fprintf(cgiOut, "
上传文件成功.
\n"); -
- //关闭文件
- cgiFormFileClose(file);
- free(tmp);
- fclose(fd);
-
- //跳转回到主页面,这个需要浏览器html代码功能来实现
- //fprintf(cgiOut,"");
- return ErrSucceed;
-
-
- }
上述CGI程序的编译需要注意一点,一般有cgiMain(及其他CGI的API)需要链接静态库(或直接带上cgic.c,同样性质),比如最终编译生成的目标文件为upload.cgi,则可按照下面的语句进行编译:
- 交叉编译工具链按实际使用的来,下述只是示例。
-
- 方式一:
- arm-linux-gcc -o upload.cgi upload.c -L ./-lcgic
-
- 方式二:
- arm-linux-gcc -o upload.cgi upload.c cgic.c
前期曾尝试直接通过html + js实现文件的上传功能,以期省点空间,无奈出现过4xx、3xx错误,解决了后还是没有上传成功,有知晓的同学还望指点一二。