2010年4月30日星期五

$_SERVER详解(转)

转:http://hi.baidu.com/thisuc/blog/item/cb634400b36756de267fb512.html

$_SERVER详解
2009-05-26 09:49
php编程中经常需要用到一些服务器的一些资料,现搜集如下:

$_SERVER['HTTP_ACCEPT_LANGUAGE']//浏览器语言
$_SERVER['REMOTE_ADDR'] //当前用户 IP 。
$_SERVER['REMOTE_HOST'] //当前用户主机名
$_SERVER['REQUEST_URI'] //URL
$_SERVER['REMOTE_PORT'] //端口。
$_SERVER['SERVER_NAME'] //服务器主机的名称。
$_SERVER['PHP_SELF']//正在执行脚本的文件名
$_SERVER['argv'] //传递给该脚本的参数。
$_SERVER['argc'] //传递给程序的命令行参数的个数。
$_SERVER['GATEWAY_INTERFACE']//CGI 规范的版本。
$_SERVER['SERVER_SOFTWARE'] //服务器标识的字串
$_SERVER['SERVER_PROTOCOL'] //请求页面时通信协议的名称和版本
$_SERVER['REQUEST_METHOD']//访问页面时的请求方法
$_SERVER['QUERY_STRING'] //查询(query)的字符串。
$_SERVER['DOCUMENT_ROOT'] //当前运行脚本所在的文档根目录
$_SERVER['HTTP_ACCEPT'] //当前请求的 Accept: 头部的内容。
$_SERVER['HTTP_ACCEPT_CHARSET'] //当前请求的 Accept-Charset: 头部的内容。
$_SERVER['HTTP_ACCEPT_ENCODING'] //当前请求的 Accept-Encoding: 头部的内容
$_SERVER['HTTP_CONNECTION'] //当前请求的 Connection: 头部的内容。例如:“Keep-Alive”。
$_SERVER['HTTP_HOST'] //当前请求的 Host: 头部的内容。
$_SERVER['HTTP_REFERER'] //链接到当前页面的前一页面的 URL 地址。
$_SERVER['HTTP_USER_AGENT'] //当前请求的 User_Agent: 头部的内容。
$_SERVER['HTTPS']//如果通过https访问,则被设为一个非空的值(on),否则返回off
$_SERVER['SCRIPT_FILENAME'] #当前执行脚本的绝对路径名。
$_SERVER['SERVER_ADMIN'] #管理员信息
$_SERVER['SERVER_PORT'] #服务器所使用的端口
$_SERVER['SERVER_SIGNATURE'] #包含服务器版本和虚拟主机名的字符串。
$_SERVER['PATH_TRANSLATED'] #当前脚本所在文件系统(不是文档根目录)的基本路径。
$_SERVER['SCRIPT_NAME'] #包含当前脚本的路径。这在页面需要指向自己时非常有用。
$_SERVER['PHP_AUTH_USER'] #当 PHP 运行在 Apache 模块方式下,并且正在使用 HTTP 认证功能,这个变量便是用户输入的用户名。
$_SERVER['PHP_AUTH_PW'] #当 PHP 运行在 Apache 模块方式下,并且正在使用 HTTP 认证功能,这个变量便是用户输入的密码。
$_SERVER['AUTH_TYPE'] #当 PHP 运行在 Apache 模块方式下,并且正在使用 HTTP 认证功能,这个变量便是认证的类型

客户端IP相关的变量
1. $_SERVER['REMOTE_ADDR']; 客户端IP,有可能是用户的IP,也有可能是代理的IP。

2. $_SERVER['HTTP_CLIENT_IP']; 代理端的IP,可能存在,可伪造。

3. $_SERVER['HTTP_X_FORWARDED_FOR']; 用户是在哪个IP使用的代理,可能存在,可以伪造。

服务器端IP相关的变量
1. $SERVER_NAME,需要使用函数gethostbyname()获得。这个变量无论在服务器端还是客户端均能正确显示。

2. $HTTP_SERVER_VARS["SERVER_ADDR"],在服务器端测试:127.0.0.1(这个与httpd.conf中BindAddress的设置值相关)。在客户端测试结果正确。

3. $_SERVER['LOCAL_ADDR'] 、$HTTP_SERVER_VARS['LOCAL_ADDR'],测试中,未获得任何结果(测试环境PHP5)。

完整的获得IP类

/**
* Get Client/Server IP
*
* @author Yaron (http://yaron.org.cn)
* @version 0.1
* @package
*/

class getIP{
function clientIP(){
$cIP = getenv('REMOTE_ADDR');
$cIP1 = getenv('HTTP_X_FORWARDED_FOR');
$cIP2 = getenv('HTTP_CLIENT_IP');
$cIP1 ? $cIP = $cIP1 : null;
$cIP2 ? $cIP = $cIP2 : null;
return $cIP;
}
function serverIP(){
return gethostbyname($_SERVER_NAME);
}
}

$getIP = new getIP();
$clientIp = getIP::clientIP();
$serverIp = getIP::serverIP();

echo 'Client IP is ',$clientIp,'
';
echo 'Server IP is ',$serverIp,'
';

php中 HTTP_HOST 和 SERVER_NAME 的区别(转)

转:http://www.akii.org/2009-01/php-in-the-difference-between-http_host-and-server_name/

PHP的SERVER保留变量中HTTP_HOST 和 SERVER_NAME经常是一样的,原因是服务器端口是80,
那么HTTP_HOST将省略不显示,而HTTP服务的默认端口就是80,所以大多数情况下,HTTP_HOST都没有显示这个端口号。

而如果使用的是ssl链接,那么端口号将被显示出来。

如果你的程序中有设定端口的功能,则可以考虑使用SERVER_NAME

否则,建议使用HTTP_HOST

PHPBB中有一句很经典的语句:

$server_name = (!empty($_SERVER['HTTP_HOST'])) ? strtolower($_SERVER['HTTP_HOST']) : ((!empty($_SERVER['SERVER_NAME'])) ? $_SERVER['SERVER_NAME'] : getenv('SERVER_NAME'));

所以HTTP_HOST = SERVER_NAME:SERVER_PORT

erlang 数值计算

7.12 Arithmetic Expressions

op Expr
Expr1 op Expr2
op Description Argument type
+ unary + number
- unary - number
+ number
- number
* number
/ floating point division number
bnot unary bitwise not integer
div integer division integer
rem integer remainder of X/Y integer
band bitwise and integer
bor bitwise or integer
bxor arithmetic bitwise xor integer
bsl arithmetic bitshift left integer
bsr bitshift right integer
Table 7.2: Arithmetic Operators.

2010年4月29日星期四

端口复用 -- socket编程:SO_REUSEADDR例解 (转)



转载 端口复用 -- socket编程:SO_REUSEADDR例解 收藏

网友vmstat多次提出了这个问题:SO_REUSEADDR有什么用处和怎么使用。而且很多网友在编写网络程序时也会遇到这个问题。所以特意写了这么一篇文章,希望能够解答一些人的疑难。
其实这个问题在Richard Stevens的《Unix网络编程指南》卷一里有很详细的解答(中文版P166-168页)。这里我只是写几个基本的例子来验证这个问题。
首先声明一个问题:当两个socket的address和port相冲突,而你又想重用地址和端口,则旧的socket和新的socket都要已经被设置了SO_REUSEADDR特性,只有两者之一有这个特性还是有问题的。
SO_REUSEADDR可以用在以下四种情况下。
(摘自《Unix网络编程》卷一,即UNPv1)
1、当有一个有相同本地地址和端口的socket1处于TIME_WAIT状态时,而你启动的程序的socket2要占用该地址和端口,你的程序就要用到该选项。
2、SO_REUSEADDR允许同一port上启动同一服务器的多个实例(多个进程)。但每个实例绑定的IP地址是不能相同的。在有多块网卡或用IP Alias技术的机器可以测试这种情况。
3、SO_REUSEADDR允许单个进程绑定相同的端口到多个socket上,但每个socket绑定的ip地址不同。这和2很相似,区别请看UNPv1。
4、SO_REUSEADDR允许完全相同的地址和端口的重复绑定。但这只用于UDP的多播,不用于TCP。

例子1:测试上面第一种情况。
#include
#include
#include
#include
#include

#define MAXLINE 100

int main(int argc, char** argv)
{
int listenfd,connfd;
struct sockaddr_in servaddr;
char buff[MAXLINE+1];
time_t ticks;
unsigned short port;
int flag=1,len=sizeof(int);

port=10013;
if( (listenfd=socket(AF_INET,SOCK_STREAM,0)) == -1)
{
perror("socket");
exit(1);
}
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family=AF_INET;
servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
servaddr.sin_port=htons(port);
if( setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &flag, len) == -
1)
{
perror("setsockopt");
exit(1);
}
if( bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr)) ==
-1)
{
perror("bind");
exit(1);
}
else
printf("bind call OK!\n");
if( listen(listenfd,5) == -1)
{
perror("listen");
exit(1);
}
for(;;)
{
if( (connfd=accept(listenfd,(struct sockaddr*)NULL,NULL)) == -1)

{
perror("accept");
exit(1);
}
if( fork() == 0)/**//*child process*/
{
close(listenfd);/**//*这句不能少,原因请大家想想就知道了。*/
ticks=time(NULL);
snprintf(buff,100,"%.24s\r\n",ctime(&ticks));
write(connfd,buff,strlen(buff));
close(connfd);
sleep(1);
execlp("f1-9d",NULL);
perror("execlp");
exit(1);
}
close(connfd);
exit(0);/**//* end parent*/
}
}
测试:编译为f1-9d程序,放到一个自己PATH环境变量里的某个路径里,例如$HO
ME/bin,运行f1-9d,然后telnet localhost 10013看结果。

2、第二种情况我没有环境测,所以就不给测试程序了,大家有条件的可以自己写
一个来测试一下。

3、测试第三种情况的程序
#include
#include
#include
#include
#include

#define MAXLINE 100

int main(int argc, char** argv)
{
int fd1,fd2;
struct sockaddr_in servaddr1,servaddr2;
char buff[MAXLINE+1];
time_t ticks;
unsigned short port;
int flag=1,len=sizeof(int);

port=10013;
if( (fd1=socket(AF_INET,SOCK_STREAM,0)) == -1)
{
perror("socket");
exit(1);
}
if( (fd2=socket(AF_INET,SOCK_STREAM,0)) == -1)
{
perror("socket");
exit(1);
}
bzero(&servaddr1,sizeof(servaddr1));
bzero(&servaddr2,sizeof(servaddr2));
servaddr1.sin_family=AF_INET;
servaddr2.sin_family=AF_INET;

if( inet_pton(AF_INET, "127.0.0.1", &servaddr1.sin_addr) <= 0)
{
printf("inet_pton() call error:127.0.0.1\n");
exit(1);
}
if( inet_pton(AF_INET, "128.160.1.230", &servaddr2.sin_addr) <= 0)

{
printf("inet_pton() call error:128.160.1.230\n");
exit(1);
}
servaddr1.sin_port=htons(port);
servaddr2.sin_port=htons(port);
if( setsockopt(fd1, SOL_SOCKET, SO_REUSEADDR, &flag, len) == -1)
{
perror("setsockopt");
exit(1);
}
if( setsockopt(fd2, SOL_SOCKET, SO_REUSEADDR, &flag, len) == -1)
{
perror("setsockopt");
exit(1);
}
if( bind(fd1,(struct sockaddr*)&servaddr1,sizeof(servaddr1)) == -1)

{
perror("bind fd1");
exit(1);
}
if( bind(fd2,(struct sockaddr*)&servaddr2,sizeof(servaddr2)) == -1)

{
perror("bind fd2");
exit(1);
}
printf("bind fd1 and fd2 OK!\n");
/**//*put other process here*/
getchar();
exit(0);/**//* end */
}

4、由于第四种情况只用于UDP的多播,和TCP的使用没多大关系,所以就不写测试
例子了。自己有兴趣的可以写。

以上的程序都是在Linux下编译通过的。也可以在其他unix平台运行。

参考资料:
1、《Unix网络编程》卷一 R. Stevens
2、《Socket programming FAQ》 http://www.ibrado.com/sock-faq/


原文地址 http://www.cppblog.com/ace/archive/2007/12.html

使用erlang连接php的cgi处理方式(转)

天真的以为找到了最快的解决方案, 看了下代码发现虽然这种方式是利用 open_port,但所有的数据传输 居然用的是 ENV,我倒 玩玩可以,生产环境就是找死了. 其实作者的需求直接用ports 就好了,数据传输可以用 json
为了更好控制还是要走fastcgi 协议,继续改 yaws_cgi.erl. 在协议分析上绕的脑袋大了, 想玩erlang,而不被erlang玩还需要个漫长的过程... 从协议解析开始..

转:http://bbs.chinaunix.net/viewthread.php?tid=1632957

-module(test).
-export([cgi_worker/0]).


cgi_worker() ->
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","d:/www"},
{"DOCUMENT_ROOT_MOUNT","/"},
{"SCRIPT_FILENAME","d:/www/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",
"application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,i
mage/png,*/*;q=0.5"},
{"HTTP_USER_AGENT",
"Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.0 (KHTML
, like Gecko) Chrome/4.0.206.1 Safari/532.0"},
{"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访问相关配置
CGIPort = open_port({spawn, "f:/PHP/php-cgi.exe"},%%Port方式对外交互
[{env, Env},
{cd, "d:/www"},
exit_status,
binary]),
cgi_get_line({start, CGIPort}).


%%获取结果
cgi_get_line({start, Port}) ->
receive
{Port, {data,Data}} ->
io:fwrite("DATA:~p~n", [Data]);
{Port, {exit_status, 0}} ->
io:fwrite("~p~n", [{exit_status, 0}]);
{Port, {exit_status, Status}} when Status /=0 ->
io:fwrite("~p~n", [{exit_status, Status}]);
_Other ->
io:fwrite("~p~n", [_Other])
end.
复制代码


php脚本
< ?php
echo 'ello php-cgi!';
? >
复制代码


以上纯粹直接构造,使用时请根据每个人环境加以修改,编译后运行如下:

67> c(test).
{ok,test}
68> test:cgi_worker().
DATA:<<"X-Powered-By: PHP/5.2.6\r\nContent-type: text/html\r\n\r\nhello php-cgi!">>
ok



说明连接并执行成功,erlang以其强悍的网络并发处理(并非只谈性能)能力,加上php的脚本的简便,相信他们可以成为很好的互补。

2010年4月21日星期三

rabbitmq boot 策略

rabbitmq 1.7.2 在原 1.7.0 版本上重新修改了启动策略, 变得更加灵活和强大
分成几个阶段
1. 初始化检测 prepare
1. 挂载log 机制
2. 检查mnesia 数据路径
2. 启动所有依赖的 app, 包括自己[os_mon, mnesia, rabbit], 并把自己放到最后
3. application:start(rabbit)
1. 开启 rabbit_sup supervisor, 一个空的监控 用来动态挂载之下的所有业务
2. 输出欢迎信息
3. 通过 rabbit:boot_steps(), 取得整个rabbit app下按照依赖关系排序的所有module 启动项.
rabbit采用了一种机制, 可以获取到 rabbit 每一个module下的 启动项. 每一个启动 项用 -rabbit_boot_step(Step_name, [{descripte, D}, {mfa, {M,F,A}}, {enables,E},{requires, R}]), 进行声明. 所有的启动项的顺序 用有限状态机来进行 依赖关系的排序.

整个启动过程还是很优雅的, 用很少的代码解决了启动的依赖问题

2010年4月14日星期三

alarm_handler

alarm_handler

MODULE

alarm_handler

MODULE SUMMARY

An Alarm Handling Process

DESCRIPTION

The alarm handler process is a gen_event event manager process which receives alarms in the system. This process is not intended to be a complete alarm handler. It defines a place to which alarms can be sent. One simple event handler is installed in the alarm handler at start-up, but users are encouraged to write and install their own handlers.

The simple event handler sends all alarms as info reports to the error logger, and saves all of them in a list which can be passed to a user defined event handler, which may be installed at a later stage. The list can grow large if many alarms are generated. So it is a good reason to install a better user defined handler.

There are functions to set and clear alarms. The format of alarms are defined by the user. For example, an event handler for SNMP could be defined, together with an alarm MIB.

The alarm handler is part of the SASL application.

When writing new event handlers for the alarm handler, the following events must be handled:

{set_alarm, {AlarmId, AlarmDescr}}

This event is generated by alarm_handler:set_alarm({AlarmId, AlarmDecsr}).

{clear_alarm, AlarmId}

This event is generated by alarm_handler:clear_alarm(AlarmId).

The default simple handler is called alarm_handler and it may be exchanged by calling gen_event:swap_handler/3 as gen_event:swap_handler(alarm_handler, {alarm_handler, swap}, {NewHandler, Args}). NewHandler:init({Args, {alarm_handler, Alarms}}) is called. Refer to gen_event(3) for further details.

EXPORTS

clear_alarm(AlarmId) -> void()

Types:

AlarmId = term()

Clears all alarms with id AlarmId.

get_alarms() -> [alarm()]

Returns a list of all active alarms. This function can only be used when the simple handler is installed.

set_alarm(alarm())

Types:

alarm() = {AlarmId, AlarmDescription}
AlarmId = term()
AlarmDescription = term()

Sets an alarm with id AlarmId. This id is used at a later stage when the alarm is cleared.

See Also

error_logger(3), gen_event(3)

2010年4月12日星期一

erlang 常用 misc(补充ing)

erlang:which(file). 对于已经加载到系统中的所有模块, 都可以定位它们的文件位置, 也可用它来了解是否已经加载此模块

rb 系列 rb:start/0 rb:start/1 rb:list/0 rb:list/1 rb:show/1 rb:grep/1
其中 rb:list(error) rb:show(error) 比较好用

ets:tab2list/1: 查看ets 数据太方便了
mnesia:table_info/2 查看mnesia table 信息
mnesia:sync_transaction 分布式开发时比较好用, 避免其它节点负载过大造成的影响

关于eralng性能调优必看的帖子 http://www.javaeye.com/topic/107476

2010年4月1日星期四

erlang 获取环境信息命令

code:get_path(). %获取当前加载路径的设定值
code:lib_dir(rpcengine, ebin). %获取库位置
code:all_loaded(). %返回所有已经
init:get_argument(home). init:get_arguments().
例如:
% erl -a b c -a d
...
1> init:get_argument(a).
{ok,[["b","c"],["d"]]}

erlang 获取自定义属性信息

xxx:module_info(). %module_info 是每次模块在编译时自动创建
beam_lib("xxxx.beam", [attributes]).chunkid() = "Abst" | "Attr" | "CInf"
chunkid() = "Abst" | "Attr" | "CInf"
| "ExpT" | "ImpT" | "LocT"
| "Atom"
chunkname() = abstract_code | attributes | compile_info
| exports | labeled_exports
| imports | indexed_imports
| locals | labeled_locals
| atoms

chunkref() = chunkname() | chunkid()
chunks(Beam, [ChunkRef]) -> {ok, {Module, [ChunkData]}} | {error, beam_lib, Reason}