mongoose 文件上传-表单形式

本文介绍了如何使用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 函数修改为:

int main(void) 
{

  signal(SIGINT, signal_handler);
  signal(SIGTERM, signal_handler);

  struct mg_mgr mgr;

  mg_mgr_init(&mgr);
  mg_log_set(MG_LL_DEBUG);  // Set log level
  mg_http_listen(&mgr, "http://192.168.2.103:8000", cb, NULL);

  while (s_signal == 0)
  {
    mg_mgr_poll(&mgr, 50);
  }
  
  
  mg_mgr_free(&mgr);

  return 0;
}

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

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

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

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

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

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

// Also, consider changing -DMG_IO_SIZE=SOME_BIG_VALUE to increase IO buffer
// increment when reading data.
static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
  if (ev == MG_EV_HTTP_MSG) {
    struct mg_http_message *hm = (struct mg_http_message *) ev_data;
    MG_INFO(("New request to: [%.*s], body size: %lu", (int) hm->uri.len,
             hm->uri.ptr, (unsigned long) hm->body.len));
    if (mg_http_match_uri(hm, "/upload")) {
      struct mg_http_part part;
      size_t ofs = 0;
      while ((ofs = mg_http_next_multipart(hm->body, ofs, &part)) > 0) {
        MG_INFO(("Chunk name: [%.*s] filename: [%.*s] length: %lu bytes",
                 (int) part.name.len, part.name.ptr, (int) part.filename.len,
                 part.filename.ptr, (unsigned long) part.body.len));
      }
      mg_http_reply(c, 200, "", "Thank you!");
    } else {
      struct mg_http_serve_opts opts = {.root_dir = "web_root"};
      mg_http_serve_dir(c, ev_data, &opts);
    }
  }
}

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

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

static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
  // printf("event type = %d\n", ev);
  if (ev == MG_EV_HTTP_MSG) {
    struct mg_http_message *hm = (struct mg_http_message *) ev_data;
    MG_INFO(("New request to: [%.*s], body size: %lu", (int) hm->uri.len,
             hm->uri.ptr, (unsigned long) hm->body.len));
    if (mg_http_match_uri(hm, "/upload")) {
      struct mg_http_part part;
      size_t ofs = 0;
      FILE *fp = NULL;
      char fileName[128] = {0};
      
      while ((ofs = mg_http_next_multipart(hm->body, ofs, &part)) > 0) {
        MG_INFO(("Chunk name: [%.*s] filename: [%.*s] length: %lu bytes",
                 (int) part.name.len, part.name.ptr, (int) part.filename.len,
                 part.filename.ptr, (unsigned long) part.body.len));
        memcpy(fileName, part.name.ptr, part.name.len);
        if(strstr(fileName, "file") != NULL) {
          memset(fileName, 0, sizeof(fileName));
          memcpy(fileName, part.filename.ptr, part.filename.len);
          if((fp = fopen(fileName, "w+")) == NULL) {
            printf("create file(%s) fail\n", fileName);
          }
          fwrite(part.body.ptr, part.body.len, 1, fp);
        }
      }
      if(fp != NULL) {
        fclose(fp);
      }
      mg_http_reply(c, 200, "", "Thank you!");
    } else {
      struct mg_http_serve_opts opts = {.root_dir = "web_root"};
      mg_http_serve_dir(c, ev_data, &opts);
    }
  }
}

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

 

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

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值