精华内容
下载资源
问答
  • C语言编写高并发Http文件上传下载服务器前言项目效果图项目介绍环境介绍程序结构之:event相关程序结构之:http相关第一种 获取文件列表类 POST请求第二种 获取文件列表类 GET请求第三种 获取文件内容类 GET请求源码...

    前言

    前段时间学习tinyhttpd和libevent开源库。
    别人的代码写的再好终究是别人的,自以为看懂了,等到自己真正写的时候就会发现有各种问题。于是准备参考libevent里面最最最基础的功能(捡了芝麻丢了西瓜?),自己写一个event,用于熟悉libevent的I/O多路复用思想。然后再加上http。就有了这篇博客的Http高并发文件上传下载服务器(这里其实是伪高并发,下文会具体描述,原谅我的标题党,哈哈)。
    共享代码给大家。希望可以帮助初学者熟悉http协议和libevent基础知识。如有问题,请大家不吝指出,谢谢!

    项目效果图

    1. 服务器启动
      在这里插入图片描述
    2. 使用客户端(浏览器)访问效果,这里是chrome
      在这里插入图片描述

    项目介绍

    这里只是简单介绍下,具体细节请大家看代码,文章最后贴有代码地址。

    环境介绍

    系统平台:windows
    开发工具:vs2010
    开发语言:C

    程序结构之:event相关

    单线程,使用I/O多路复用实现并发。main函数进来后直接调用http_startup()。

    int main()
    {
        UINT16 port = 80;
        http_startup(&port);
        return 0;
    }
    

    http_startup()里面创建一个socket用于listen,然后把这个socket扔到event里面,设置回调函数为accept_callback,等待客户端(这里就是各种浏览器)连接。所贴代码为了逻辑清晰,去掉了一些代码。

    int http_startup(uint16_t *port)
    {
        SOCKET fd;
        event_t ev = {0};
        network_listen(port, &fd);
        ev.fd = fd;
        ev.type = EV_READ | EV_PERSIST;
        ev.callback = accept_callback;
        event_add(&ev);
        // dispatch里面就是个死循环,保证程序不退出
        event_dispatch();
        closesocket(fd);
        return SUCC;
    }
    

    下面贴上event的核心,也就是event_dispatch()
    为了逻辑清晰,也去掉了一些代码。
    这里就是所谓的伪高并发之一了(后面还有之二):
    由于是windows系统没有epoll,为了简单使用了select模型。尽管重新定义了FD_SETSIZE为1024,但是还是无关痛痒。1024个连接就满了,而且select是轮询机制,效率受限。
    开始准备使用iocp,一来api的名字太难看了,就懒得研究了。二来我就是用来写个demo练练手,select也能凑合着用。
    伪高并发之二:
    网络I/O使用的是阻塞I/O,比如recv,会阻塞。上传文件时每次读取BUFFER_UNIT个数据,测试时log打印发现还是会偶尔阻塞一会。把BUFFER_UNIT改小的可能会有所改善,但是也不是解决办法。应该改成非阻塞I/O。这里也不讨论这个问题了。
    #define BUFFER_UNIT 4096

    ret_code_t event_dispatch()
    {
        fd_set readfds;
        fd_set writefds;
        fd_set exceptfds;
        struct timeval timeout = { 0, 500000 };
        int ret;
        uint32_t i;
    
        while (TRUE)
        {
            _active_size = 0;
            memcpy(&readfds, &_readfds, sizeof(_readfds.fd_count) + _readfds.fd_count * sizeof(SOCKET));
            memcpy(&writefds, &_writefds, sizeof(_writefds.fd_count) + _writefds.fd_count * sizeof(SOCKET));
            memcpy(&exceptfds, &_exceptfds, sizeof(_exceptfds.fd_count) + _exceptfds.fd_count * sizeof(SOCKET));
    
            ret = select(0, &readfds, &writefds, &exceptfds, &timeout);
            switch (ret)
            {
            case 0: // the time limit expired
                break;
            case SOCKET_ERROR: // an error occurred
                log_error("{%s:%d} an error occurred at select. WSAGetLastError=%d", __FUNCTION__, __LINE__, WSAGetLastError());
                return FAIL;
            default: // the total number of socket handles that are ready
                for (i=0; i<readfds.fd_count; i++)
                {
                    _active_ns[_active_size++] = find_rbnode(readfds.fd_array[i], &_read_evs);
                }
                for (i=0; i<writefds.fd_count; i++)
                {
                    _active_ns[_active_size++] = find_rbnode(writefds.fd_array[i], &_write_evs);
                }
                for (i=0; i<exceptfds.fd_count; i++)
                {
                    _active_ns[_active_size++] = find_rbnode(exceptfds.fd_array[i], &_except_evs);
                }
                break;
            }
    
            for (i = 0; i < _active_size; i++)
            {
                _active_ns[i]->ev->callback(_active_ns[i]->ev);
            }
        }
        return SUCC;
    }
    

    再下面就是event_add()和event_del()。这三个函数基本上就是event驱动模型的全部了,贴代码。老规矩,去掉部分空指针判断的代码。影响阅读代码逻辑

    ret_code_t event_add(event_t *ev)
    {
        struct rbnode_t  k;
        struct rbnode_t *n = NULL;
        struct rbtree_t *t = NULL;
        fd_set          *s = NULL;
        if (ev->type & EV_READ)
        {
            t = &_read_evs;
            s = &_readfds;
        }
        else if (ev->type & EV_WRITE)
        {
            t = &_write_evs;
            s = &_writefds;
        }
        else if (ev->type & EV_EXCEPT)
        {
            t = &_except_evs;
            s = &_exceptfds;
        }
        k.ev = ev;
        n = RB_FIND(rbtree_t, t, &k);
        if (n)
        {
            log_warn("{%s:%d} event is already exist, fd=%d", __FUNCTION__, __LINE__, ev->fd);
            return EXIS;
        }
        n = create_rbnode(ev);
        RB_INSERT(rbtree_t, t, n);
        FD_SET(ev->fd, s);
        return SUCC;
    }
    

    实际代码里面由于业务逻辑,这段代码与所贴不一致,哈哈

    static int event_del(uint32_t fd, struct rbtree_t *t, fd_set *s)
    {
        struct rbnode_t  k;
        struct rbnode_t *n = NULL;
        event_t e = { 0 };
        
        e.fd = fd;
        k.ev = &e;
        n = RB_FIND(rbtree_t, t, &k);
        if (n)
        {
            RB_REMOVE(rbtree_t, t, n);
            FD_CLR(fd, s);
            release_rbnode(n);
        }
        return SUCC;
    }
    

    程序结构之:http相关

    本程序目前能支持的客户端请求有三种:

    第一种 客户端(浏览器)上传文件类 POST请求

    判断逻辑如下:uri以 /upload 开头,
    本来开始是没有后面的 ?path=,后来发现服务器不知道保存到哪级目录下面,于是就加上了这个。
    如下url:

    http://localhost/upload?path=
    http://localhost/upload?path=Debug/
    

    使用form表单提交,html上传代码如下:
    html代码都是服务端按逻辑生成的。

    <form action="/upload?path=Debug/" method="post" enctype="multipart/form-data">
    <input type="file" name="file" />
    <input type="submit" value="Upload" />
    </form>
    

    第二种 获取文件列表类 GET请求

    代码里面的response_home_page()函数。
    判断逻辑如下:request头里面的uri以 / 结尾,如下url:

    http://localhost/
    http://localhost/Debug/
    http://localhost/Debug/httpd.tlog/
    

    第三种 获取文件内容类 GET请求

    代码里面的response_send_file_page()函数。
    判断逻辑如下:非以上两种情况,如下url:

    http://localhost/event.c
    http://localhost/Debug/event.obj
    http://localhost/Debug/httpd.tlog/link.write.1.tlog
    

    先写这么多了,以后有时间再补充吧。(耐不住懒啊 ~)大家有问题请留言。


    源码地址:

    CSDN下载: https://download.csdn.net/download/yu1121jm/10695695
    Github: https://github.com/binbyu/httpd

    展开全文
  • C 语言实现的http文件上传下载服务 系统平台:windows 开发工具:vs2010 开发语言:C 程序为单线程,使用I/O多路复用实现并发 抽取libevent的最最最基础框架,自己封装event 使用BSD tree.h的红黑树
  • 通过腾讯云云函数 SCF 可以实现对象存储 COS 中的文件自动解压缩、其中 COS 用于存储上传后需要解压的 .zip 文件及解压后的文件,SCF 实现对 .zip 文件上传至 COS 后的自动解压缩。同时还适用于对相关音视频文件上传...

    背景

    通过腾讯云云函数 SCF 可以实现对象存储 COS 中的文件自动解压缩、其中 COS 用于存储上传后需要解压的 .zip 文件及解压后的文件,SCF 实现对 .zip 文件上传至 COS 后的自动解压缩。同时还适用于对相关音视频文件上传到COS之后进行编解码、格式转换,裁剪等场景。

    COS + 云函数运行原理原理
    在云端,可以通过云函数(SCF)和 COS 产品进行联动,完成自动化业务逻辑处理,也就是所谓的事件驱动:
    支持一键配置 COS 事件监听,无需额外设备投入,即可实时消费 COS 事件;
    自定义处理逻辑,支持多种编程语言,支持第三方库;
    毫秒级弹性伸缩,轻松应对负载的波峰波谷,现网实际案例支持10W+级QPS,且像COS一样,支持按实际使用付费;
    高可用,针对云函数的运行状态,支持配置多维度的监控告警,实时感知健康状态。
    在这里插入图片描述
    通过上面的原理图我们可以看出,在使用腾讯云对象存储上传之后,可以通过配置将上传事件触发为云函数SCF运行,然后在函数里面对文件执行处理,并且通过云函数弹性伸缩能力,支持应对高并发带来的可扩展。满足并发性能和成本的考虑。

    方案详解

    整个方案如下图所示:
    在这里插入图片描述

    具体操作步骤如下
    1、创建存储桶并进行配置。
    在这里插入图片描述

    2、配置解压函数
    在这里插入图片描述
    在这里插入图片描述

    3、部署验证执行
    在这里插入图片描述

    展开全文
  • 项目描述工具类包封装了一些关于分片md5验证、断点续传、分片上传、等方法前端...分块上传 也是归属于断点续传的基础功能之一,前端大文件分块后端组合,断点续传也是重传出错的这个分块文件秒传 上传前验证md5,服...

    项目描述

    工具类包封装了一些关于分片md5验证、断点续传、分片上传、等方法

    前端样例使用百度插件 WebUploader , 插件的源码还是有一定的问题的

    分片上传是需要前后端高度配合的

    功能:断点续传 本次最主要的基础功能,在断网或者在暂停的情况下,能够在上传断点中继续上传。

    分块上传 也是归属于断点续传的基础功能之一,前端大文件分块后端组合,断点续传也是重传出错的这个分块

    文件秒传 上传前验证md5 ,服务端返回一个代表这个文件已经上传了的状态,前端跳过这个文件

    普通上传 顺带着写了一个

    并发上传 这个是前端插件的功能

    上传速率 依据两次上传的时间差 / 两次上传的文件差 得出

    前端略微修改了一些 WebUploader 官方的JS

    新增了dialogOpen事件、文件新增file.uploadRate(上传速率)属性

    附:doc文档

    运行环境

    jdk8+tomcat+IntelliJ IDEA+maven

    项目技术(必填)

    springBoot + web-uploader

    运行视频

    链接:https://pan.baidu.com/s/1r_xJFAU1BK4G6IGqWCFMGA

    提取码:28au

    展开全文
  • 继上次大文件分块上传原理第二弹见:http://blog.csdn.net/haohao123nana/article/details/54692669,有童靴说前端分片递归上传效率不,我试了试前端并发上传。本地上传测试,700M的视频,用递归上传用了4分钟,...

    继上次大文件分块上传原理第二弹见:http://blog.csdn.net/haohao123nana/article/details/54692669,有童靴说前端分片递归上传效率不高,我试了试前端并发上传。。
    browser-md5-file.js 下载地址https://github.com/forsigner/browser-md5-file
    md5.js 下载地址 https://www.npmjs.com/package/js-md5
    后端文件跟第二弹的一样,前端html更改成并发上传分块了
    经过测试支持 1.2G的文件上传

    html

    <!DOCTYPE HTML>
    <html>
    <head>
        <meta charset="utf-8">
        <title>HTML5大文件分片上传示例</title>
        <script src="http://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script>
        <script src="md5.js"></script>
        <script src="browser-md5-file.js"></script>
        <script>
            //vari = -1;
            var shardSize = 5 * 1024 * 1024;    //以5MB为一个分片
            var succeed = 0;
            var databgein;  //开始时间
            var dataend;    //结束时间
            var page = {
                init: function () {
                    $("#upload").click(function () {
                        databgein = new Date();
                        var file = $("#file")[0].files[0];  //文件对象
                        isUpload(file);
                    });
                }
            };
            $(function () {
                page.init();
            });
            function isUpload(file) {
             //构造一个表单,FormData是HTML5新增的
              var form = new FormData();
              browserMD5File(file, function (err, md5) {
                   form.append("md5", md5);
                    //Ajax提交
                    $.ajax({
                        url: "http://localhost:8080/bookQr/test/isUpload",
                        type: "POST",
                        data: form,
                        async: true,        //异步
                        processData: false,  //很重要,告诉jquery不要对form进行处理
                        contentType: false,  //很重要,指定为false才能形成正确的Content-Type
                        success: function (data) {
                            var dataObj = eval("(" + data + ")");
                            var uuid = dataObj.fileId;
                            var date = dataObj.date;
                            if (dataObj.flag == "1") {
                                //没有上传过文件,开始分片上传文件
                                repeatupload(file, uuid, md5, date);
                            } else if (dataObj.flag == "2") {
                                //已经上传部分
                                upload(file, uuid, md5, date);
                            } else if (dataObj.flag == "3") {
                                //文件已经上传过
                                alert("文件已经上传过,秒传了!!");
                                $("#uuid").append(uuid);
                            }
                        }, error: function (XMLHttpRequest, textStatus, errorThrown) {
                            alert("服务器出错!");
                        }
    
                    });
              });
    
            }
            function repeatupload(file, uuid, filemd5, date) {
                name = file.name;        //文件名
                size = file.size;        //总大小
                shardCount = Math.ceil(size / shardSize);  //总片数
    
                for (var i = 0; i < shardCount; i++) {
                    upload2(file, uuid, filemd5, date, i,1);
                }
            }
            /*
             *上传每一分片
             * file 文件对象
             * uuid 后端生成的uuid
             * filemd5 整个文件的md5
             * date  文件第一个分片上传的日期(如:20170122)
             * i  文件第i个分片
             * type  1为检测;2为上传
             */
            function upload2(file, uuid, filemd5, date, i,type) {
                //计算每一片的起始与结束位置
                var start = i * shardSize,
                        end = Math.min(size, start + shardSize);
                //构造一个表单,FormData是HTML5新增的
                var form = new FormData();
                if (type === 1) {
                    form.append("action", "check");  //检测分片是否上传
                    $("#param").append("action==check ");
                } else {
                    form.append("action", "upload");  //直接上传分片
                    form.append("data", file.slice(start, end));  //slice方法用于切出文件的一部分
                    $("#param").append("action==upload ");
                }
    
                form.append("uuid", uuid);
                form.append("filemd5", filemd5);
                form.append("date", date);
                form.append("name", name);
                form.append("size", size);
                form.append("total", shardCount);  //总片数
                form.append("index", i+1);        //当前是第几片
    
                var ssindex = i+1;
                $("#param").append("index==" + ssindex + "<br/>");
    
                //按大小切割文件段  
                var data = file.slice(start, end);
                var r = new FileReader();
                r.readAsBinaryString(data);
    
                $(r).load(function (e) {
                    var bolb = e.target.result;
                    var md5 = hex_md5(bolb);
                    form.append("md5", md5);
                    //Ajax提交
                    $.ajax({
                        url: "http://localhost:8080/bookQr/test/upload",
                        type: "POST",
                        data: form,
                        async: true,        //异步
                        processData: false,  //很重要,告诉jquery不要对form进行处理
                        contentType: false,  //很重要,指定为false才能形成正确的Content-Type
                        success: function (data) {
                            var dataObj = eval("(" + data + ")");
                            var fileuuid = dataObj.fileId;
                            var flag = dataObj.flag;
                            //服务器返回该分片是否上传过
                            if (type === 1) {
                                if (flag == "1") {
                                    //未上传,继续上传 
                                    upload2(file, uuid, filemd5, date,i,2);
                                } else if (dataObj.flag == "2") {
                                    //已上传
                                    action = false;
                                    ++succeed;
                                }
    
                            } else {
                                //服务器返回分片是否上传成功
                                ++succeed;//改变界面
                                $("#output").text(succeed + " / " + shardCount);
    
                                if (i+1  == shardCount) {
                                    dataend = new Date();
                                    $("#uuid").append(fileuuid);
                                    $("#usetime").append(dataend.getTime() - databgein.getTime());
                                }
    
                            }
                        }, error: function (XMLHttpRequest, textStatus, errorThrown) {
                            alert("服务器出错!");
                        }
    
                    });
    
                })
    
            }
        </script>
    </head>
    <body>
    
    <input type="file" id="file"/>
    <button id="upload">上传</button>
    <span id="output" style="font-size:12px">等待</span>
    
    <span id="usetime" style="font-size:12px;margin-left:20px;">用时</span>
    
    <span id="uuid" style="font-size:12px;margin-left:20px;">uuid==</span>
    <br/>
    
    <br/>
    <br/>
    <br/>
    <span id="param" style="font-size:12px;margin-left:20px;">param==</span>
    
    
    </body>
    
    </html>
    
    
    

    最后下载地址: http://download.csdn.net/download/haohao123nana/10015607

    展开全文
  • 最初业务需求:将文件从ftp下到本地并上传到hdfs,其中ftp到本地和本地到hdfs皆有文件完整性校验,ftp到本地的逻辑由于和业务耦合度较,因此本文不再叙述,这里仅说一下从本地到hdfs的并发脚本相关说明及代码实现...
  • 首先,对于大家而言,想必对网络传输并不陌生,因为我们每天都在下载“文件”。嘻嘻!!!但是如果让我们自己写一个网络文件传输的程序,估计大家都傻眼了,今天小编就给大家以最简单的方式,让C#初学者能够快速开发...
  • NetCore文件上传两种方式  NetCore官方给出的两种文件上传方式分别为“缓冲”、“流式”。我简单的说说两种的区别, ... 文件上传所用的资源(磁盘、内存)取决于并发文件上传的数量和大小。 如果应用尝试
  • 本篇,我们则来讲讲Nginx的几种性能优化方式。...如果不了解cpu的核数,可以top命令之后按1看出来,也可以查看/proc/cpuinfo文件 grep ^processor /proc/cpuinfo | wc -l。[root@lx~]# vi/usr/local/nginx1.10/conf...
  • 高并发架构解析

    2021-02-24 00:48:35
    高并发经常会发生在有大活跃用户量,用户高聚集的业务场景...一个可以支持高并发的服务少不了好的服务器架构,需要有均衡负载,数据库需要主从集群,nosql缓存需要主从集群,静态文件需要上传cdn,这些都是能让业务程序
  • 用SocketAsyncEventArgs通讯封装、服务端实现日志查看、SCOKET列表、上传、下载、远程文件流、吞吐量协议,测试SocketAsyncEventArgs的性能和压力,最大连接数支持65535个长连接,最高命令交互速度达到250MB/S(使用...
  • 一、关于七牛上传、下载高并发说明 二、七牛分片下载实际运用 关于七牛大文件下载机制调研   1、分片下载介绍 七牛有提供【分片下载】功能,关于range说明如下:使用场景:针对WIFI和移动网络切换时,及时暂停...
  • 高并发复用数据库链接技术详解之数据库连接池 类加载器的高级特性(自定义类加器实现加密解密) iBATIS开源主流框架(实现半自动化hibernate) 企业实用技能之详解(眼睛横纹模式验证码防止恶意登陆) 动态页面的静态化...
  • 高并发经常会发生在有大活跃用户量,用户高聚集的业务场景中,如:...一个可以支持高并发的服务少不了好的服务器架构,需要有均衡负载,数据库需要主从集群,nosql缓存需要主从集群,静态文件需要上传cdn,这些都是能
  • 大话高并发架构

    2017-02-06 17:37:52
     一个可以支持高并发的服务少不了好的服务器架构,需要有均衡负载,数据库需要主从集群,nosql缓存需要主从集群,静态文件需要上传cdn,这些都是能让业务程序流畅运行的强大后盾。 大致需要用到的服务器架构如下:...
  • 问题:目前想做一个文件传输服务器,可以进行上传下载文件操作,希望支持高并发连接。 查资料大多服务器采用单I/O线程+多工作线程模型实现。I/O线程负责监听和分发事件,工作线程处理事件。 想知道这种模型是否适合...
  • 非常非常快的文件系统,可以同时存储海量大文件和小文件高并发存储视频音乐和图片等非常棒并且可以作为列存储示例:(这不仅是极致简单的,而且是最快的)//上传文件,只需一行//?如果文件特别大怎么办,...
  • celery实现高并发

    千次阅读 2018-11-22 15:40:21
    Celery适用异步处理问题,比如发送邮件、文件上传,图像处理等等比较耗时的操作,我们可将其异步执行,这样用户不需要等待很久,提高用户体验 2.Celery特点: 简单,易于使用和维护,有丰富的文档 高效,...
  • Libevent C++高并发网络编程

    千人学习 2019-04-13 23:37:36
    讲解HTTP服务端开发示例,HTTP客户端请求开 发示例,最后基于 LIBEVENTT创建线程池C++框架,并用此框架完成FTP 服务器的登录、目录访问、文件上传下载能功能。 开发环境 操作系统: windows1064位和 ubuntu18....
  • 2、多图片同时ajax上传 通过防并发设置防止可能出现的覆盖;3、图片实时上传后支持 在新窗口中打开查看; 使用 main.js import Vue from 'vue'; import ElementUI from 'element-ui' import 'element...
  • 高并发网站架构

    2018-06-25 14:50:28
    基础概念 ... 请求方法:GET,POST,HEAD,PUT,DELETE,MOVE GET: 访问网站,得到的文字和图片 POST:把你的数据提交到远程去...PUT:上传文件 DELETE:删除文件 MOVE:跳转 常见的状态码网页 200:正常 3...
  • Hi ! 我是小小,今天是本周的第六...业务从初期到成熟,从单一到集群,最后到分布式,需要有服务器的负载均衡,数据的主从复制,nosql的各种集群,静态文件上传cdn等等。 需要用到的服务器架构如下 服务器 负载均衡,.
  • 服务器生成缩略图的时机一般分为两种:上传文件时生成、访问时生成,下面为大家介绍下php根据url自动生成缩略图并处理高并发问题

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 395
精华内容 158
关键字:

高并发文件上传