• mongoose 文件上传-表单形式


            这个 mongoose 源码是github 上最新的源码,其下载地址为 mongoose github 源码,此篇文章介绍的是其中一个 example: file-upload-html-form,是一个表单形式的文件上传方式,此 example 介绍教程在这里:file_uploads 。源码下载、编译,及调试,其中遇到一些问题,记录如下。

            按照其教程,通过浏览器来进行文件的上传,如:

            这个意思是要在浏览器地址栏输入:http://localhost:8000 ,这个得根据实际情况进行输入,如果程序是在本机运行,同时你也是通过本机的浏览器的话,这样输入是没问题的。而我的实际情况是,程序在CentOS 系统上运行,但我是在 Window10 上操作文件上传,则这个地址中的 localhost 要相应地修改成 CentOS 系统的 IP 地址。如我的 CentOS 系统 IP 地址为:192.168.2.103,则代码里的 main 函数修改为:

    1. int main(void)
    2. {
    3. signal(SIGINT, signal_handler);
    4. signal(SIGTERM, signal_handler);
    5. struct mg_mgr mgr;
    6. mg_mgr_init(&mgr);
    7. mg_log_set(MG_LL_DEBUG); // Set log level
    8. mg_http_listen(&mgr, "http://192.168.2.103:8000", cb, NULL);
    9. while (s_signal == 0)
    10. {
    11. mg_mgr_poll(&mgr, 50);
    12. }
    13. mg_mgr_free(&mgr);
    14. return 0;
    15. }

            IP 地址写死或通过参数传入,这个随意。

            当代码编译且运行起来后,通过浏览器进行访问 http://192.168.2.103:8000 ,但服务端却没有任何反应,加了一个打印信息,看回调函数是否被调用到:

    event type = 2,查看代码是 MG_EV_POLL 事件,回调函数被调用,属于正常的,但访问时为何没有连接的反应呢?原来是请求被 CentOS  防火墙挡住了,需要关闭才能正常访问,我的系统信息是这样的:

    关闭命令为:systemctl stop firewalld。关闭后再访问则显示了这个页面:

    选择一个小的文本文件上传,打印输出如下: 

    但实际文件并没有写到服务器端,源码里只是打印了信息,并没有写文件,原源码为:

    1. // Also, consider changing -DMG_IO_SIZE=SOME_BIG_VALUE to increase IO buffer
    2. // increment when reading data.
    3. static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
    4. if (ev == MG_EV_HTTP_MSG) {
    5. struct mg_http_message *hm = (struct mg_http_message *) ev_data;
    6. MG_INFO(("New request to: [%.*s], body size: %lu", (int) hm->uri.len,
    7. hm->uri.ptr, (unsigned long) hm->body.len));
    8. if (mg_http_match_uri(hm, "/upload")) {
    9. struct mg_http_part part;
    10. size_t ofs = 0;
    11. while ((ofs = mg_http_next_multipart(hm->body, ofs, &part)) > 0) {
    12. MG_INFO(("Chunk name: [%.*s] filename: [%.*s] length: %lu bytes",
    13. (int) part.name.len, part.name.ptr, (int) part.filename.len,
    14. part.filename.ptr, (unsigned long) part.body.len));
    15. }
    16. mg_http_reply(c, 200, "", "Thank you!");
    17. } else {
    18. struct mg_http_serve_opts opts = {.root_dir = "web_root"};
    19. mg_http_serve_dir(c, ev_data, &opts);
    20. }
    21. }
    22. }

     根据它教程里的解释,Mongoose接收该请求,将其完全缓冲到内存中,然后使用mg_http_next_multipart() 函数遍历每个表单字段。上传文件的全部内容被缓存到了 body 里了。

    所以我们可以把 body 内容写下来,那就是上传的文件的内容了,修改回调函数代码如下:

    1. static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
    2. // printf("event type = %d\n", ev);
    3. if (ev == MG_EV_HTTP_MSG) {
    4. struct mg_http_message *hm = (struct mg_http_message *) ev_data;
    5. MG_INFO(("New request to: [%.*s], body size: %lu", (int) hm->uri.len,
    6. hm->uri.ptr, (unsigned long) hm->body.len));
    7. if (mg_http_match_uri(hm, "/upload")) {
    8. struct mg_http_part part;
    9. size_t ofs = 0;
    10. FILE *fp = NULL;
    11. char fileName[128] = {0};
    12. while ((ofs = mg_http_next_multipart(hm->body, ofs, &part)) > 0) {
    13. MG_INFO(("Chunk name: [%.*s] filename: [%.*s] length: %lu bytes",
    14. (int) part.name.len, part.name.ptr, (int) part.filename.len,
    15. part.filename.ptr, (unsigned long) part.body.len));
    16. memcpy(fileName, part.name.ptr, part.name.len);
    17. if(strstr(fileName, "file") != NULL) {
    18. memset(fileName, 0, sizeof(fileName));
    19. memcpy(fileName, part.filename.ptr, part.filename.len);
    20. if((fp = fopen(fileName, "w+")) == NULL) {
    21. printf("create file(%s) fail\n", fileName);
    22. }
    23. fwrite(part.body.ptr, part.body.len, 1, fp);
    24. }
    25. }
    26. if(fp != NULL) {
    27. fclose(fp);
    28. }
    29. mg_http_reply(c, 200, "", "Thank you!");
    30. } else {
    31. struct mg_http_serve_opts opts = {.root_dir = "web_root"};
    32. mg_http_serve_dir(c, ev_data, &opts);
    33. }
    34. }
    35. }

     其实就添加了创建文件、写文件、关闭文件 代码。选择一个小的文本文件进行上传:

     

    上传成功的。这个例子只合适上传一般的文本文件,像其他的二进制的文件是用到了其他的例子,这里不作介绍。 

  • 相关阅读:
    在Windows环境下配置及安装Nacos
    【Redis】list常用命令&内部编码&使用场景
    学生HTML个人网页作业作品:基于HTML实现教育培训机构网站模板毕业源码(8页)
    MAC M1芯片安装mounty读写移动硬盘中的文件
    c++11的一些新特性
    new IntersectionObserver 使用笔记
    linux-conda环境安装教程
    VMware 安装CentOS7
    网络编程——socket定义和地址格式
    七大常见基于比较的排序算法
  • 原文地址:https://blog.csdn.net/tianyexing2008/article/details/126924819