写这个程序主要是为了熟悉它的语法。
功能:一个假WEB服务器,很多缺陷,还要完善。
使用:
1.编译web.erl。然后在ERLANG环境中用命令web:start().启动。
2.文件请求,你把文件放在当前目录下,如hello.html,输入http://localhost:8800/hello.html.
3.数据请求(相当于JAVA中的servlet),当你输入http://localhost:8800/erlang/mode/func的时候,它回去请求一个叫mode:func(Param)的函数,其中Param是GET和POST传递过来的参数,函数返回值会被传送到页面,当然你必须先编译了这个模块。
4.如果请求失败,也许会导致程序崩溃,哈哈,比如文件不存在。
下面是源代码:
-module(web).
-export([start/0]).
%%启动服务
start() ->
{ok, LSock} = gen_tcp:listen(8800, [binary, {packet, 0},{active, false}]),
seq_loop(LSock).
%%请求队列循环
seq_loop(LSock) ->
{ok, Sock} = gen_tcp:accept(LSock),
req_loop(Sock),
seq_loop(LSock).
%%请求处理循环
req_loop(Sock) ->
case gen_tcp:recv(Sock, 0) of
{ok, Req} ->
ok = analyse(Req),
respones(Sock),
req_loop(Sock);
{error, closed} ->
ok
end.
%%回应
respones(Sock)->
S = case get(mode) of
erlang ->
apply(get(module),get(func),[lists:append(get(get),get(post))]);
_ ->
io:format("~p~n",[get(file)]),
{ok,DATA} = file:read_file(get(file)),
DATA
end,
ok = gen_tcp:send(Sock, S),
ok = gen_tcp:close(Sock).
%% 请求分析
analyse(Req) ->
[H|T]= string:tokens(binary_to_list(Req),"/r/n"),
%获得请求路径和请求GET参数
[M,P,V] = string:tokens(H," "),
put(method,M),
put(ver,V),
%%分析GET参数
PP = string:tokens(P,"?"),
case length(PP) of
2 ->
[H1|[T1]]=PP,
server(H1),
put(get,param(T1));
_ ->
[PP1]=PP,
server(PP1)
end,
put(server,P),
ok = analyse1(T),
ok.
analyse1([H|T]) ->
M = string:tokens(H,":"),
case length(M) of
1 -> %post参数
[M1]=M,
put(post,param(M1)),
analyse1(T);
2 ->
[K,V]=M,
case K of
"Accept-Language" ->
put(language,V),
analyse1(T);
"Accept-Encoding" ->
put(encoding,V),
analyse1(T);
_ ->
analyse1(T)
end;
3 ->
[_,IP,PORT] = M,
put(host,IP),
put(port,PORT),
analyse1(T);
_ ->
analyse1(T)
end;
analyse1([]) ->
ok.
%分析请求服务类型,如果get为/erlang/[Mod]/[Fun]则为请求数据服务,否则为文件请求
server(P) ->
[H|T]=string:tokens(P,"/"),
case H of
"erlang" ->
[Mod|[Fun]]=T,
put(mode,erlang),
put(module,list_to_atom(Mod)),
put(func,list_to_atom(Fun));
_ ->
[_H1|T1]=P,
put(mode,file),
put(file,T1)
end.
%格式化参数
param(Pas) ->
Pa= string:tokens(Pas,"&"),
param(Pa,[]).
param([H|T],P) ->
M = string:tokens(H,"="),
case length(M) of
1 ->
param(T,[{M,nil}|P]);
2 ->
[H1|[T1]]= M,
param(T,[{H1,T1}|P]);
_ ->
param(T,P)
end;
param([],P) ->
P.