用 C 语言手撸了一个 HTTP 服务器,求关注 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
爱意满满的作品展示区。
monkeyNik
V2EX    分享创造

用 C 语言手撸了一个 HTTP 服务器,求关注

  •  
  •   a href="/member/monkeyNik">monkeyNik
    Water-Melon 2023-10-14 09:51:58 +08:00 2526 次点击
    这是一个创建于 729 天前的主题,其中的信息可能已经有所发展或是发生改变。

    大家好,近来用 C 语言从头写了一个 HTTP 服务器。

    这个服务器有点类似于 openresty 和 PHP 的混合体,它的特性如下:

    • 使用脚本语言处理每个请求
    • 脚本解释器与 HTTP 收发(即 HTTP 服务器)处于同一个线程
    • 每个处理请求的脚本有完全隔离的运行环境
    • 当一个请求的处理不慎陷入死循环时,不会影响其他请求的处理,也不会影响新建 TCP

    前两点有点类似 openresty ,第三点有点类似 PHP 的运行环境。

    不过因为时间比较短,因此也有一些限制和不完善的地方,例如:

    • 暂时只支持 HTTP 1.x
    • 暂时只支持短链接
    • 暂不支持 chunk mode

    给出一个示例演示一下。

    我们可以使用如下脚本处理请求:

    //entry.m /* * Implement a simple controller. * There are three variable injected in this script task: * 1. Req. Its prototype is: * Req { * method; //string e.g. GET POST DELETE ... * version; //string e.g. HTTP/1.0 HTTP/1.1 * uri; //string e.g. /index/index * args; //an key-value array, e.g. ["key":"val", ...] * headers; //an key-value array, e.g. ["Content-Type":"application/json", ...] * body; //string * } * * 2. Resp. Its prototype is: * Resp { * version; //same as Req's version * code; //integer e.g. 200 * headers; //same as Req's headers * body; //same as Req's body * } * *. 3. Basedir. A string of the base directory path. (Not used in this example) */ #include "@/index.m" str = Import('str'); sys = Import('sys'); uri = str.slice(Req.uri, '/'); uri && (ctlr = str.capitalize(uri[0]), o = $ctlr); if (!o || sys.has(o, uri[1]) != 'method') { Resp.code = 404; } else { o.__action__ = uri[1]; Resp.body = o.__action__(); Resp.headers['Content-Length'] = str.strlen(Resp.body); } 

    上面这个脚本简单来说,就是实现了一个简单的控制器( MVC 中的 C )。

    下面这段代码用来处理对应 URI 的请求。

    //index.m Json = Import('json'); Index { @index() { Resp.headers['Content-Type'] = 'application/json'; return Json.encode(['code': 200, 'msg': 'OK']); } } 

    然后启动程序:

    medge -p 8080 

    最后使用 curl 测试一下:

    $ curl -v -H "Host: test.com" http://127.0.0.1:8080/index/index * Trying 127.0.0.1:8080... * Connected to 127.0.0.1 (127.0.0.1) port 8080 (#0) > GET /index/index HTTP/1.1 > Host: test.com > User-Agent: curl/7.81.0 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 200 OK < Content-Length: 23 < Content-Type: application/json < * Connection #0 to host 127.0.0.1 left intact {"code":200,"msg":"OK"} 

    项目的 Github 仓库:Medge

    感兴趣的小伙伴还望不吝你的小星星~

    感谢大家!

    sadfQED2
        1
    sadfQED2  
       2023-10-14 10:40:30 +08:00 via Android
    跟 openresty+lua 比有啥优势?
    monkeyNik
        2
    monkeyNik  
    OP
       2023-10-14 10:54:50 +08:00 via iPhone
    @sadfQED2 其实适用的场景就不一样,也谈不上优势了。提及 openresty 的原因是将脚本与服务器整合的想法一样。特性上的不同就是,这个东西的脚本不会出现类似_G 那种多请求间存在共享的问题,也不会出现单请求死循环导致其他所有请求都裂开的问题
    sadfQED2
        3
    sadfQED2  
       2023-10-14 11:17:40 +08:00 via Android
    @monkeyNik 你这个定位是拿来写业务逻辑的还是写网关逻辑?写网关逻辑我觉得多请求共享应该是优势才对,方便资源共享,减少消耗。
    monkeyNik
        4
    monkeyNik  
    OP
       2023-10-14 12:49:45 +08:00 via iPhone
    @sadfQED2 不是网关逻辑,就是一些 web API 开发的
    WinterWu
        5
    WinterWu  
       2023-10-15 20:29:05 +08:00
    如果是做业务逻辑,核心是写后端逻辑才是更复杂的事情。
    monkeyNik
        6
    monkeyNik  
    OP
       2023-10-16 09:32:20 +08:00 via iPhone
    @WinterWu 是的,逻辑可以使用脚本来完成 脚本支持了常用的库以及和数据库通信的部分
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2823 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 27ms UTC 00:22 PVG 08:22 LAX 17:22 JFK 20:22
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86