- 论坛徽章:
- 0
|
本帖最后由 bs 于 2010-05-04 21:49 编辑
Erlang做为高并发(c100K)连接前端,后端使用fast-cgi构建多语言开发平台,甚至负载均衡/分布式应用,
本文以php-fpm为例说明:
php脚本代码:- <?php
- echo 'hello world!';
- ?>
复制代码 erlang代码:- -module(fcgi).
- -export([start/0]).
- start() ->
- Env = [{"SERVER_SOFTWARE","test web server"},
- {"SERVER_NAME","localhost"},
- {"HTTP_HOST","localhost"},
- {"GATEWAY_INTERFACE","CGI/1.1"},
- {"SERVER_PROTOCOL","HTTP/1.1"},
- {"SERVER_PORT","8080"},
- {"REQUEST_METHOD","GET"},
- {"REQUEST_URI","/t.php"},
- {"DOCUMENT_ROOT","/var/www/erlang"},
- {"DOCUMENT_ROOT_MOUNT","/"},
- {"SCRIPT_FILENAME","/var/www/erlang/t.php"},
- {"PATH_INFO",[]},
- {"PATH_TRANSLATED",[]},
- {"SCRIPT_NAME","/t.php"},
- {"REMOTE_ADDR","127.0.0.1"},
- {"REMOTE_HOST","127.0.0.1"},
- {"SERVER_ADDR","127.0.0.1"},
- {"LOCAL_ADDR","127.0.0.1"},
- {"QUERY_STRING",[]},
- {"HTTP_ACCEPT",
- "text/html;q=0.9,text/plain;q=0.5"},
- {"HTTP_USER_AGENT","unknow"},
- {"HTTP_ACCEPT_CHARSET","GBK,utf-8;q=0.7,*;q=0.3"},
- {"HTTP_ACCEPT_LANGUAGE","zh-CN,zh;q=0.8"},
- {"HTTP_ACCEPT_ENCODING","gzip,deflate,sdch"},
- {"HTTP_CACHE_CONTROL","max-age=0"}],%%构造http访问相关配置
- {ok, Socket}=gen_tcp:connect("127.0.0.1",9000,[binary, {packet, 0}],10000),
- %%发送初始请求8字节
- fcgi_send_record(Socket,1,
- 1, %%fast-cgi requestID application,下同
- <<1:16,0:8,0:40>>), %%<<1:16,是否长连接1或0:8,填充:40>>
- %%请求内容
- fcgi_send_record(Socket, 4, %%fast-cgi类型参数,下同
- 1, Env),
- %%完成
- fcgi_send_record(Socket, 4,1, []),
- recv_msg(Socket),
- gen_tcp:close(Socket).
- %%返回内容接收
- recv_msg(Socket) ->
- receive
- {tcp, Socket, Bin} ->
- %%原报文<<Version:8, Type:8, RequestId:16, ContentLength:16,PaddingLength:8, Reserved:8,Str/binary >> = Bin,
- <<_:32,ContentLength:16,_:16,Str/binary >> = Bin,
- %%计算输出内容长度
- Dlen=ContentLength-53,
- %%获取内容
- << _H:53/binary,Data:Dlen/binary,_Other/binary >> = Str,
- io:format("Received msg: ~p~n", [Data]);
- _other ->
- io:format("Other msg: ~p~n", [_other]),
- recv_msg(Socket),
- error
- after 3000 ->io:format("Time out.~n")
- end.
- %%发送选项
- fcgi_send_record(Socket, Type, RequestId, NameValueList) ->
- EncodedRecord = fcgi_encode_record(Type, RequestId,NameValueList),
- gen_tcp:send(Socket, EncodedRecord).
- %%组包
- fcgi_encode_record(Type, RequestId, NameValueList)
- when is_list(NameValueList) ->
- fcgi_encode_record(Type, RequestId,fcgi_encode_name_value_list(NameValueList));
- %%判断ContentData是否满8字节,否则填充
- fcgi_encode_record(Type, RequestId, ContentData)
- when is_binary(ContentData) ->
- ContentLength = size(ContentData),
- PaddingLength = if
- ContentLength rem 8 == 0 ->
- 0;
- true ->
- 8 - (ContentLength rem 8)
- end,
- %%填充数据,每8字节组包 不足用0填充
- PaddingData = <<0:(PaddingLength*8)>>,
- Version = 1,
- Reserved = 0,
- <<Version:8,
- Type:8,
- RequestId:16,
- ContentLength:16,
- PaddingLength:8,
- Reserved:8,
- ContentData/binary,
- PaddingData/binary >>.
- %%将环境变量组成binary
- fcgi_encode_name_value_list(_NameValueList = []) ->
- << >>;
- fcgi_encode_name_value_list(_NameValueList = [{Name, Value} | Tail]) ->
- <<(fcgi_encode_name_value(Name,Value))/binary,(fcgi_encode_name_value_list(Tail))/binary >>.
- fcgi_encode_name_value(Name, _Value = undefined) ->
- fcgi_encode_name_value(Name, "");
- fcgi_encode_name_value(Name, Value) when is_list(Name) and is_list(Value) ->
- NameSize = length(Name),
- NameSizeData = << NameSize:8 >>,
- ValueSize = length(Value),
- ValueSizeData = <<ValueSize:8 >>,
- << NameSizeData/binary,
- ValueSizeData/binary,
- (list_to_binary(Name))/binary,
- (list_to_binary(Value))/binary >>.
复制代码 在Eshell下:
>fcgi:start().
Received msg: <<"hello world!">>
ok
初始内容数据:
ContentData=<<Role:16,
KeepConn:8, %%是否长连接
0:40 %%填充数据
>>
环境变量内容数据(样例):
- ContentData=[{"SERVER_SOFTWARE","test web server"},
- {"SERVER_NAME","localhost"},
- {"HTTP_HOST","localhost"},
- {"GATEWAY_INTERFACE","CGI/1.1"},
- {"SERVER_PROTOCOL","HTTP/1.1"},
- {"SERVER_PORT","8080"},
- {"REQUEST_METHOD","GET"},
- {"REQUEST_URI","/t.php"},
- {"DOCUMENT_ROOT","/var/www/erlang"},
- {"DOCUMENT_ROOT_MOUNT","/"},
- {"SCRIPT_FILENAME","/var/www/erlang/t.php"},
- {"PATH_INFO",[]},
- {"PATH_TRANSLATED",[]},
- {"SCRIPT_NAME","/t.php"},
- {"REMOTE_ADDR","127.0.0.1"},
- {"REMOTE_HOST","127.0.0.1"},
- {"SERVER_ADDR","127.0.0.1"},
- {"LOCAL_ADDR","127.0.0.1"},
- {"QUERY_STRING",[]},
- {"HTTP_ACCEPT",
- "text/html;q=0.9,text/plain;q=0.5"},
- {"HTTP_USER_AGENT","unknow"},
- {"HTTP_ACCEPT_CHARSET","GBK,utf-8;q=0.7,*;q=0.3"},
- {"HTTP_ACCEPT_LANGUAGE","zh-CN,zh;q=0.8"},
- {"HTTP_ACCEPT_ENCODING","gzip,deflate,sdch"},
- {"HTTP_CACHE_CONTROL","max-age=0"}],%%构造http访问相关配置
复制代码 通信报文:
<<Version:8,
Type:8,
RequestId:16,
ContentLen:16, %%内容长度
PaddingLength:8, %%填充长度
Reserved:8,
ContentData/binary, %%内容数据
PaddingData/binary %%填充数据
>>.
返回的内容,前8个字节数据如下:
<<Version:8, Type:8, RequestId:16, ContentLength:16,PaddingLength:8, Reserved:8,
Data/binary>>
Data为处理结果数据,类似 <<"X-Powered-By: PHP/5.2.13\r\nContent-type: text/html\r\n\r\nhello world!">>
ContentLength既fastcgi处理结果数据的长度(字节).
原先CGI版本:
http://bbs.chinaunix.net/thread-1632957-1-1.html |
|