Goahead编译
Goahead 编译
目录说明
Makefile #顶层Makefile,可以自动检测当前运行平台的环境,并调用projects的mk
projects #子层的Makefile,有各个平台的
test # web 文件以及路由和配置文件
#可以看到直接make 输出如下
make --no-print-directory -f projects/goahead-linux-default.mk all
# 安装
sudo make install
Ubuntu编译
make
make
sudo make install
selfkey处理
reallin@ubuntu:/work/goahead/goahead-5.0.1$ sudo goahead -v --home /etc/goahead /var/www/goahead
goahead: 0: Unable to read key self.key
goahead: 0: Cannot initialize server. Exiting.
sudo cp ./build/linux-x64-default/bin/self.key /etc/goahead
sudo cp ./build/linux-x64-default/bin/self.crt /etc/goahead
测试
#./goahead -v --home 配置文件路径 文档路径 绑定IP:监听端口
#./goahead -v --home /etc/goahead /var/www/goahead 0.0.0.0:8888
sudo goahead -v --home /etc/goahead /var/www/goahead
# 下面是运行结果
goahead: 2: Configuration for Embedthis GoAhead Community Edition
goahead: 2: ---------------------------------------------
goahead: 2: Version: 5.0.1
goahead: 2: BuildType: Debug
goahead: 2: CPU: x64
goahead: 2: OS: linux
goahead: 2: Host: 127.0.1.1
goahead: 2: Directory: /etc/goahead
goahead: 2: Documents: /var/www/goahead
goahead: 2: Configure: me -d -q -platform linux-x86-default -configure . -gen make
goahead: 2: ---------------------------------------------
goahead: 2: Started http://*:80
goahead: 2: Started https://*:443
具体的install目录
ls /etc/goahead
auth.txt route.txt self.crt self.key
ls /var/www/goahead
favicon.ico index.html # 这个就是网页了
交叉编译
# 如果有错误提示 undefined reference to `__stack_chk_fail' 加上这个选项-fno-stack-protector
make CC=arm-linux-gcc LD=arm-linux-ld CFLAGS=-fno-stack-protector
方便测试
-
cd build/linux-x64-default/bin
-
cp ../../../src/auth.txt ./
-
cp ../../../src/route.txt ./
-
新建一个
myweb
文件夹存网页 -
sudo ./goahead -v ./myweb/
-
修改配置文件route.txt
1.把route uri=/action handler=action注释掉 在前面加个#即可 然后加一句route uri=/action/ methods=GET|POST handler=action 2. 把route uri=/ extensions=jst handler=jst改为route uri=/ extensions=jst,asp,html handler=jst 如果不做修改那我们在以后写html,asp文件里的action就不能被识别
win下编译
顶层目录的make.bat
修改下,因为原来的默认工程找不到路径
projects\windows x64 nmake -f projects/goahead-windows-default.nmake %1 %2 %3 %4 %5 %6 %7 %8 %9
运行之后,打开projects
下的goahead-windows-default.sln
就可以编译了
如果要调试,需要设置调试目录为 ../../test
,加上参数-v
即可
可以选择启动项目为test或者goahead.
早期的源码流程
--------------------------------------------------------------------------------------
MAIN(goahead, int argc, char **argv, char **envp)
-------------------------------------初始化过程开始-------------------------------------
|-->for(argv[...]){} //解析命令行
|-->initPlatform(); //注册信号处理函数
|-->signal(SIGTERM, sigHandler) ...
|-->websOpen(documents, route) //初始化服务器
|-->websOsOpen(); //生成系统启动随机数(标识系统)
|-->websRuntimeOpen(); //开始系统计时sym、symMax
|-->websTimeOpen(); //初始化hash结构timeTokens
|-->logOpen(); //初始化基本日志
|-->setFileLimits(); //设置最大文件描述符值
|-->socketOpen(); //初始化WebsSocket **socketList=NULL,socketMax =0,socketHighestFd=-1
|-->setLocalHost(); //设置服务器的hostname(websHost), 服务器的IP地址(websIpAddr)
|-->sslOpen(); //若支持ssl则初始化ssl相关信息
|-->sessions = hashCreate(-1); //初始化话hash结构sessions
|-->websStartEvent(...pruneSessions...); //启动定时调度函数pruneSessions ,pruneSessions每秒调度清除过期的sessions
|-->websSetDocuments(documents); //设置goahead访问根目录websDocuments
|-->websOpenRoute(); //初始化hash结构handlers,相应函数加入到handlers中.
|-->websDefineHandler("continue", continueHandler, 0, 0, 0); //continue的处理函数为continueHandler
|-->websDefineHandler("redirect", redirectHandler, 0, 0, 0); //redirect处理函数为redirectHandler
|-->websCgiOpen(); //定义cgi处理函数加入到handlers中.
|-->websDefineHandler("cgi", 0, cgiHandler, 0, 0); //定义cgi的处理函数为cgiHandler
|-->websOptionsOpen(); //定义options处理函数加入到handlers中.
|-->websDefineHandler("options", 0, optionsHandler, 0, 0); //定义options的处理函数为optionsHandler
|-->websActionOpen(); //初始化hash结构actionTable,定义action处理函数加入到handlers中,定义action对应值的函数加入到actionTable中. .
|-->websDefineHandler("action", 0, actionHandler, closeAction, 0); //定义action的处理函数为actionHandler
|-->WebActionDefineInit(); //初始化action对应值的处理函数
|-->websDefineAction("upgrade", ActionDefault); //定义action=upgrade的处理函数为ActionDefault,
|-->websDefineAction("...", ...); //同上的类似函数
|-->websFileOpen(); //设置默认页面websIndex="index.html",定义action处理函数加入到handlers中
|-->websDefineHandler("file", 0, fileHandler, fileClose, 0); //定义file的处理函数为fileHandler
|-->websUploadOpen(); //设置上传文件路径uploadDir = "/tmp",定义upload处理函数加入到handlers中
|-->websDefineHandler("upload", 0, uploadHandler, 0, 0); //定义upload的处理函数为uploadHandler
|-->websJstOpen(); //初始化hash结构websJstFunctions,定义write处理函数加入到websJstWrite中,定义jst处理函数加入到jstHandler中.
|-->websDefineJst("write", websJstWrite); //定义jst(javascript)的write的处理函数为websJstWrite,支持<% write("text"); %>
|-->websDefineHandler("jst", 0, jstHandler, closeJst, 0); //定义jst(javascript)的处理函数为jstHandler
|-->websOpenAuth(0); //初始化认证相关处理函数
|-->websDefineAction("userlogin", ActionUserLoginProc); //定义action=userlogin的处理函数为ActionUserLoginProc
|-->websDefineAction("userlogout", ActionUserLogoutProc); //定义action=userlogin的处理函数为ActionUserLoginProc
|-->verifyPassword = websVerifyPasswordFromFile; //设置验证密码函数
|-->websFsOpen(0); //初始化hash结构romFs,定义ME_ROM相关文件路径
|-->websLoad(routeFile); //load route.txt配置文件
|-->route = websAddRoute(uri, handler, -1) //将结构为WebsRoute的route加入hash结构routes中,初始化route中uri和handler
|-->websSetRouteMatch(route, dir, protocol, methods, extensions, abilities, redirects); //初始化route中protocol等
|-->websSetRouteAuth(route, auth) //初始化route中authType等
|-->for(websMimeList){hashEnter(websMime)} //初始化goahead默认支持的content type
|-->open(accessLog, O_CREAT | O_TRUNC | O_APPEND | O_WRONLY, 0666) //初始化access.log log日志文件
|-->websLoad(auth) //load auth.txt配置文件
|-->websAddRole(name, abilities) //增加管理角色,如role name=manager abilities=view,edit,delete
|--> websAddUser(username, password, roles) //增加管理用户,如user name=admin password=xx roles=manager,purchaser
---------------------------------------初始化过程结束-------------------------------------------
|-->logHeader(); //日志打印goahead基本配置信息
|-->websListen(endpoint) //初始化socket并监听
|-->socketParseAddress(endpoint, &ip, &port, &secure, 80); //解析监听ip 端口
|-->sid = socketListen(ip, port, websAccept, 0) //创建socket,并监听,初始化WebsSocket结构加入到socketlist中
|-->listens[listenMax++] = sid //保存socket的WebsSocket信息到listens中
|-->websGetBackground() //使用daemon(0, 0)设置后台运行
---------------------------------------主循环处理开始-------------------------------------------
|-->websServiceEvents(&finished); //while(!finished){}主循环
|-->socketSelect(-1, delay) //select socket
|-->nEvents = select(socketHighestFd + 1, (fd_set *) readFds, (fd_set *) writeFds, (fd_set *) exceptFds, &tv); //select socket
|-->socketProcess() //处理请求
|-->socketDoEvent(sp);
|-->socketAccept(sp); //accept新请求
|-->newSock = accept(sp->sock, addr, (Socklen*) &len) //accept 新socket
|-->nid = socketAlloc(sp->ip, sp->port, sp->accept, sp->flags); //分配并初始化新的WebsSocket,加入到socketList[nid]
|-->socketList[nid] ->sock = newSock ... //继续初始化新的socketList[nid]的WebsSocket结构
|-->(sp->accept)(nid, ipbuf, port, sp->sid) //调用websAccept函数, nid为新建请求的socketid, ipbuf为远端IP,port为远端port, sp->sid为本机监听的socketid
|-->wid = websAlloc(sid);wp=webs[wid]; //根据参数sid(即nid)分配并初始化新的Webs,加入到webs[wid]
|-->initWebs(wp, 0, 0); //初始化新的webs[wid]的Webs结构
|-->wp->state = WEBS_BEGIN; //初始化链接状态机初始值
|-->bufCreate(&wp->output); //初始化发送buf
|-->bufCreate(&wp->input); //初始化接收buf
|-->wp->listenSid = listenSid; ... //继续初始化新的webs[wid]的Webs结构
|-->wp->timeout = websStartEvent(PARSE_TIMEOUT, checkTimeout, (void*) wp); //设置wp的超时函数
|-->socketEvent(sid, SOCKET_READABLE, wp); //
|-->readEvent(wp); //一直调用readEvent读http和处理http,直至处理接收设置SOCKET_WRITABLE才可调用writeEvent
|-->nbytes = websRead(wp, (char*) rxbuf->endp, ME_GOAHEAD_LIMIT_BUFFER) //读取http报文
|-->websPump(wp); //根据wp->state状态机的值处理http报文
|-->case WEBS_BEGIN: parseIncoming(wp);
|-->parseFirstLine(wp); //处理http请求行,并保存到wp结构中
|-->parseHeaders(wp); //处理http请求头部,并保存到wp结构中
|-->wp->state = (wp->rxChunkState || wp->rxLen > 0) ? WEBS_CONTENT : WEBS_READY; //设置wp->state状态值
|-->websRouteRequest(wp); //设置此链接的处理函数
|-->case WEBS_CONTENT: processContent(wp);
|-->websProcessCgiData(wp); //设置此链接的处理函数jstHandler、cgiHandler、continueHandler、redirectHandler、actionHandler等
|-->case WEBS_READY: websRunRequest(wp);
|-->(*route->handler->service)(wp); //执行此链接的处理函数,
|-->hashLookup(actionTable, actionName);(*fn)((void*) wp); //以actionHandler为例,执行actionTable中对应函数,以ActionDefault为例
|-->ActionDefault
|-->websWrite_ex(webs, 0, json_object_to_json_string(obj),token); //返回页面数据
|-->jstHandler(Webs *wp); //以jstHandler为例,执行...
|-->...websDone(wp);
|-->websFlush(wp, 0); -->wp->state = WEBS_COMPLETE;
|-->socketCreateHandler(wp->sid, sp->handlerMask | SOCKET_WRITABLE, socketEvent, wp);
|-->case WEBS_RUNNING: /* Nothing to do until websDone is called */
|-->case WEBS_COMPLETE: complete(wp, 1);
|-->socketCreateHandler(wp->sid, sp->handlerMask | SOCKET_READABLE, socketEvent, wp); //初始化此链接的处理函数sp->handler=socketEvent
|-->writeEvent(wp);
|-->websFlush(wp, 0);
|-->while(websWriteSocket());
|-->wp->state = WEBS_COMPLETE;
|-->websFree(wp);
|-->(sp->handler)(sid, sp->handlerMask & sp->currentEvents, sp->handler_data) //
|-->websCgiPoll(); //如有cgi,只响应cgi
|-->websRunEvents(); //执行已加入定时器相关函数
|-->websClose(); //关闭相关资源