自己动手写服务器-1
来源:互联网 发布:jd软件 编辑:程序博客网 时间:2024/05/18 01:06
博客概述
先前关于linux文件系统驱动的博客已经删除,文件系统可能是一个比较复杂的话题,涉及的东西也比较多。我虽然想写,不过发现可能要叙述的东西太多,我没办法掌握重点,所以暂时不写,等以后有好的思路在写。根据朋友的建议,先写服务器开发的博客。首先从简单的回文服务器开始到http服务器。
博客面向的读者是已经熟悉c,unix编程和unix网络编程,然后想编写服务器程序的人。
服务器概述
大部分的服务器都是接受客户端的请求之后做一些处理,然后发回一些内容给客户端。比如回文服务器是接受一段文本,然后回射给客户端。如下给出服务器的一个图例:
一个服务器可能会和很多客户端同时交互,所以保证每个客户端公平的快速响应是很重要的。
mc_echo概述
mc_echo是一个回文服务器,也是本博客讲解的服务器开发的第一个服务器,项目地址为https://github.com/mc-robin/mc_server/tree/master/mc_echo。以下给出mc_echo的大致图例:
主进程用于接受新的客户端连接,然后分发连接请求。处理进程用于处理客户端的请求,然后回应。调度进程用于帮助主进程更加合理的分发服务。mc_echo并不涉及模块机制,所以是比较简单的服务器示例。
mc_echo配置文件解析
mc_echo的配置文件大致如下:
port{ "8888" }user{ "nobody" }group{ "nogroup" }IPversion { "ipv4" }LOGFile{ "/var/log/echo.log" }maxrequests{ "1024" }maxprocesses{ "4096" }upperthreshold{ "512" }lowerthreshold{ "64" }processcreat{ "4" }cycletime{ "60" }backlog{ "1024" }#keyfile{ "/home/mc_server/mc_echo/key.pem" }#certfile { "/home/mc_server/mc_echo/cert.pem" }
port是服务器的监听端口,user和group是服务器运行后的uid和gid(同时接受id和名字格式),ipversion是ip版本,logfile是日志文件路径,maxrequests是处理进程最多能处理的客户端数目,maxprocesses是处理进程的最大数目,upperthreshold和lowerthreshold是调度参数(细节在讲诉调度进程时解析),processcreat是预创建的处理进程数目,cycletime是调度进程的周期,backlog是listen的参数。keyfile和certfile是ssl的加密文件路径。
注: mc_echo只能监听一个端口,mc_httpd能同时监听多个端口(要实现监听多个端口本质不难,细节在讲解mc_httpd时讨论)
mc_echo采用lex和yacc读取配置文件,lex的代码如下:
%{#include "configure.h"#include "conf_yacc.h"%}or [\|,]ws [ \t\n]+comment #.*string \"[^\"\n]*[\"\n]%%{ws} ;{comment} ;{or} { return OR; }\{ { return OBRACE; }\} { return EBRACE; }{string} { yylval.dstr = strdup(yytext + 1); if(yylval.dstr[yyleng - 2] != '"'){ mc_err("Error: '%s' is Illegal string\n", yytext); }else yylval.dstr[yyleng - 2] = '\0'; return STRING; }[Uu][Ss][Ee][Rr] { return USER; }[Pp][Oo][Rr][Tt] { return PORT; }[Gg][Rr][Oo][Uu][Pp] { return GROUP; }[Cc][Ii][Pp][Hh][Ee][Rr] { return CIPHER; }[Bb][Aa][Cc][Kk][Ll][Oo][Gg] { return BACKLOG; }[Ll][Oo][Gg][Ff][Ii][Ll][Ee] { return LOGFILE; }[Pp][Ii][Dd][Ff][Ii][Ll][Ee] { return PIDFILE; }[Kk][Ee][Yy][Ff][Ii][Ll][Ee] { return KEYFILE; }[Cc][Ee][Rr][Tt][Ff][Ii][Ll][Ee] { return CERTFILE; }[Ii][Pp][Vv][Ee][Rr][Ss][Ii][Oo][Nn] { return IPVERSION; }[Cc][Yy][Cc][Ll][Ee][Tt][Ii][Mm][Ee] { return CYCLETIME; }[Mm][Aa][Xx][Rr][Ee][Qq][Uu][Ee][Ss][Tt][Ss] { return MAXREQUESTS; }[Mm][Aa][Xx][Pp][Rr][Oo][Cc][Ee][Ss][Ss][Ee][Ss] { return MAXPROCESSES; }[Pp][Rr][Oo][Cc][Ee][Ss][Ss][Cc][Rr][Ee][Aa][Tt] { return PROCESSCREAT; }[Uu][Pp][Pp][Ee][Rr][Tt][Hh][Rr][Ee][Ss][Hh][Oo][Ll][Dd] { return UPPERTHRESHOLD; }[Ll][Oo][Ww][Ee][Rr][Tt][Hh][Rr][Ee][Ss][Hh][Oo][Ll][Dd] { return LOWERTHRESHOLD; }. ;%%从代码可以看出,mc_echo的配置文件是不区分大小写的。另外,此处的代码与git上的略有不同,此处的代码更加好。
yacc的代码如下:
%{#undef YYSTACKSIZE#define YYSTACKSIZE 5000#include "configure.h"%}%union{ char *dstr;}%token PORT%token USER%token GROUP%token CIPHER%token BACKLOG%token LOGFILE%token PIDFILE%token KEYFILE%token CERTFILE%token IPVERSION%token CYCLETIME%token MAXREQUESTS%token MAXPROCESSES%token PROCESSCREAT%token UPPERTHRESHOLD%token LOWERTHRESHOLD%token OR%token OBRACE%token EBRACE%token <dstr> STRING%%configs: | config configs ;config: OBRACE STRINGS EBRACE | USER OBRACE STRING EBRACE { MC_USER_SET(mc_startup->s_configinfo.c_uid, $3) } | GROUP OBRACE STRING EBRACE { MC_GROUP_SET(mc_startup->s_configinfo.c_gid, $3) } | PORT OBRACE STRING EBRACE { MC_DIGIT_SET(mc_startup->s_configinfo.c_port, $3) } | CIPHER OBRACE STRING EBRACE { MC_STRING_SET(mc_startup->s_configinfo.c_cipher, $3) } | BACKLOG OBRACE STRING EBRACE { MC_DIGIT_SET(mc_startup->s_configinfo.c_backlog, $3) } | LOGFILE OBRACE STRING EBRACE { MC_STRING_SET(mc_startup->s_configinfo.c_logfile, $3) } | PIDFILE OBRACE STRING EBRACE { MC_STRING_SET(mc_startup->s_configinfo.c_pidfile, $3) } | KEYFILE OBRACE STRING EBRACE { MC_STRING_SET(mc_startup->s_configinfo.c_keyfile, $3) } | CERTFILE OBRACE STRING EBRACE { MC_STRING_SET(mc_startup->s_configinfo.c_certfile, $3) } | CYCLETIME OBRACE STRING EBRACE { MC_DIGIT_SET(mc_startup->s_configinfo.c_cycle, $3) } | IPVERSION OBRACE STRING EBRACE { MC_DOMAIN_SET(mc_startup->s_configinfo.c_domain, $3) } | MAXREQUESTS OBRACE STRING EBRACE { MC_DIGIT_SET(mc_startup->s_configinfo.c_schd.s_maxfds, $3) } | MAXPROCESSES OBRACE STRING EBRACE { MC_DIGIT_SET(mc_startup->s_configinfo.c_schd.s_maxprocs, $3) } | PROCESSCREAT OBRACE STRING EBRACE { MC_DIGIT_SET(mc_startup->s_configinfo.c_schd.s_medianprocs, $3) } | UPPERTHRESHOLD OBRACE STRING EBRACE { MC_DIGIT_SET(mc_startup->s_configinfo.c_schd.s_thresholdfds_u, $3) } | LOWERTHRESHOLD OBRACE STRING EBRACE { MC_DIGIT_SET(mc_startup->s_configinfo.c_schd.s_thresholdfds_l, $3) } ;STRINGS: | STRING STRINGS | STRINGS OR STRINGS ;%%intyyerror(char *s){ fprintf(stderr, "%s\n", s);}观察yacc的代码,首先第一步是重新定义默认的栈大小,因为默认的栈大小可能比较小会导致溢出,所以此处重新定义一个比较大的值。接下来是一些符号的声明。configs是一个递归的语法,config依次处理各个配置文件的值;OBRACE STRINGS EBRACE用于过滤不认识的配置,git上的代码并没有这么做,这种做法是mc_httpd上为了过滤其他模块所用的配置参数所用的办法,此处直接给出的yacc和lex代码都是根据mc_httpd的代码改写的。
下一篇博客讨论mc_echo的事件机制的代码以及多进程的模型
1 0
- 自己动手写服务器-1
- 自己动手写服务器1.1
- 自己动手写tomdog服务器
- 自己动手写服务器-2
- 第一章自己动手写服务器浏览器
- 浅析Tomcat----自己动手写服务器
- 自己动手写操作系统1
- 自己动手写的Web服务器<一>
- 深入学习Tomcat----自己动手写服务器
- 自己动手写http服务器---java版
- 自己动手写http服务器---java版
- 自己动手写http服务器---java版
- 学习笔记之自己动手写WEB服务器
- 自己动手写操作系统实验1
- 自己动手写操作系统笔记1
- 自己动手写flv文件(1)
- 自己动手写web框架----1
- 《自己动手写框架1》:缘起
- java正则表达式
- MySQL数据库事务锁等待:Lock wait timeout exceeded; try restarting transaction
- Unity项目内存优化大全
- 7.5 非线性回归:logistic Regression(逻辑回归)
- RxJava 从入门到出轨
- 自己动手写服务器-1
- JS replace()方法替换变量(可以对变量进行全文替换)
- Java基础-08总结帮助文档,代码块,继承
- MD5~单向散列加密
- SQL学习笔记
- java面试:编译时与运行时
- 扩充数据集升级版 --> 提取目标
- 使用python的Flask实现一个RESTful API服务器端[翻译]
- spring boot spring cache ehcache3.x整合