4月8日,青岛,那些旧战机、潜艇和驱逐舰
[
2012-4-11 00:03 | by 张宴 ]
2012-4-11 00:03 | by 张宴 ]
4月7日,青岛胶南,那片海、那间房、那座城
[
2012-4-11 00:01 | by 张宴 ]
2012-4-11 00:01 | by 张宴 ]
新房终于装修完了,列出各房间照片和装修费用清单
[
2012-4-5 00:07 | by 张宴 ]
2012-4-5 00:07 | by 张宴 ]
一些数据:移动iPhone用户超联通两倍,Android用户小米手机占有率第一
[
2012-2-23 13:24 | by 张宴 ]
2012-2-23 13:24 | by 张宴 ]
[文章作者:张宴 本文版本:v1.0 最后修改:2012.02.23 转载请注明原文链接:http://blog.s135.com/android_ios_status/]
上周,我们发布了一款支持 Android 和 iOS 平台手机应用。本周,又发布了另一款手机应用的 iOS 版本。纵贯两款应用的统计数据,发现有两点出乎我的意料。
1、iOS 应用状况:移动iPhone用户超联通两倍,WIFI 联网方式接近 75%
我曾经一直以为在 iPhone 4/4S 用户中,中国联通的用户要比中国移动多,毕竟联通是苹果合作伙伴,联通卡是3G网络,而移动卡的国产TD-SCDMA iPhone不支持,只能使用2G网络。但经过最近一星期发布的两款手机应用(均有 iOS、Android 版本)的统计数据发现,iPhone 里插着中国移动2G卡的用户比中国联通3G用户多两倍。因此,将来针对移动互联网 IDC 机房的选择与优化,也需要偏向中国移动网络。


2、Android 应用状况:小米手机占有率领先,WIFI 联网方式超过 80%
Android 用户移动远超联通,在预料之中。但是,没有想到,在这么多不同型号的 Android 手机中,小米手机 MI-ONE Plus 的占有量竟然能够位居第一,而三星 GT-I9100 紧跟其后。

上周,我们发布了一款支持 Android 和 iOS 平台手机应用。本周,又发布了另一款手机应用的 iOS 版本。纵贯两款应用的统计数据,发现有两点出乎我的意料。
1、iOS 应用状况:移动iPhone用户超联通两倍,WIFI 联网方式接近 75%
我曾经一直以为在 iPhone 4/4S 用户中,中国联通的用户要比中国移动多,毕竟联通是苹果合作伙伴,联通卡是3G网络,而移动卡的国产TD-SCDMA iPhone不支持,只能使用2G网络。但经过最近一星期发布的两款手机应用(均有 iOS、Android 版本)的统计数据发现,iPhone 里插着中国移动2G卡的用户比中国联通3G用户多两倍。因此,将来针对移动互联网 IDC 机房的选择与优化,也需要偏向中国移动网络。


2、Android 应用状况:小米手机占有率领先,WIFI 联网方式超过 80%
Android 用户移动远超联通,在预料之中。但是,没有想到,在这么多不同型号的 Android 手机中,小米手机 MI-ONE Plus 的占有量竟然能够位居第一,而三星 GT-I9100 紧跟其后。

根据淘宝商品 num_iid 批量生成淘宝客链接的 PHP 函数
[
2012-2-16 14:08 | by 张宴 ]
2012-2-16 14:08 | by 张宴 ]
[文章作者:张宴 本文版本:v1.0 最后修改:2012.02.16 转载请注明原文链接:http://blog.s135.com/taobaoke_click_urls/]
根据淘宝商品 num_iid 批量生成淘宝客(什么是淘宝客?)链接的 PHP 文件内容如下。
淘宝 API 有调用次数限制,一次 API 调用,可以最大返回40个商品的淘宝客链接,因此,在本函数内,如果需要批量生成的淘宝商品 num_iid 数大于40,将按照40个一次,分多次调用。如果调用淘宝 API 查询过的商品 num_iid,不管其是否有淘宝客链接(有些商品没有淘宝客推广链接),都将利用 Memcached 缓存起来,下次直接查缓存,不会重复调用淘宝 API。
淘宝开放平台(http://open.taobao.com/) PHP SDK 下载:
根据淘宝商品 num_iid 批量生成淘宝客(什么是淘宝客?)链接的 PHP 文件内容如下。
淘宝 API 有调用次数限制,一次 API 调用,可以最大返回40个商品的淘宝客链接,因此,在本函数内,如果需要批量生成的淘宝商品 num_iid 数大于40,将按照40个一次,分多次调用。如果调用淘宝 API 查询过的商品 num_iid,不管其是否有淘宝客链接(有些商品没有淘宝客推广链接),都将利用 Memcached 缓存起来,下次直接查缓存,不会重复调用淘宝 API。
<?php
require_once(dirname(__FILE__).'/TopSdk.php'); //引用淘宝开放平台 API SDK
function object2Array($d)
{
if (is_object($d))
{
$d = get_object_vars($d);
}
if (is_array($d))
{
return array_map(__FUNCTION__, $d);
}
else
{
return $d;
}
}
/*********************************************
* 函数名:get_taobaoke_link ($num_iids)
* 函数用途:通过淘宝商品 num_iids 获取其对应的淘宝客手机版链接
* 创建时间:2012-02-14
* 创建人:张宴 net@s135.com
* 参数说明:
* $num_iids 淘宝商品ID(支持多个商品)数组,示例如下:
* $num_iids[] = "13583512568";
* $num_iids[] = "10809380078";
* $num_iids[] = "10809380079";
* 返回值:
* 下标为淘宝商品 num_iid ,值为淘宝客链接 click_url 的二维数组。如果无淘宝客链接,click_url 为空字符串,示例如下:
* array(3) {
* ["13583512568"]=>
* string(191) "http://auction1.wap.taobao.com/auction/item_detail-0db2-13583512568.jhtml?tks=jUTwPLMDtUUNEZhqfEuTZqkZhGw1LA7%2BzCJBXCj27NpurHxjZN70Amg0DVaFU61pfnHwW%2FI4MZGm%0Awgb69kbb1NL8uwtu%2BDnyAunBCVDP"
* ["10809380078"]=>
* string(187) "http://auction1.wap.taobao.com/auction/item_detail-0db2-10809380078.jhtml?tks=jUTwPLMDtUUNEGWhOOgVVuX%2BJKYt7fesyuZjEe7hvmpTJxYDfK8i1Wpvfl7lwI7nzD9W8M352v6E%0AyuUtsKun81AGltKzJWCYPiVDiOeC"
* ["10809380079"]=>
* string(0) ""
* }
*********************************************/
function get_taobaoke_link ($num_iids) {
$memcache = new Memcache;
$memcache->connect('127.0.0.1', 11911); //Memcached 缓存服务器地址
$click_urls = $memcache->get($num_iids);
foreach ($num_iids AS $num_iid) {
if (!isset($click_urls[$num_iid])) {
$tbapi_num_iids_arr[] = $num_iid;
}
}
if (!empty($tbapi_num_iids_arr)) {
$numbers = count($tbapi_num_iids_arr);
$numbers_max = 40; //淘宝 API 限制最大返回40条记录
if ($numbers > 0) {
$numbers_times = ceil($numbers / $numbers_max); //第一层循环的循环次数
$numbers_start = 0;
$numbers_end = $numbers_max;
for ($numbers_i = 1; $numbers_i <= $numbers_times; $numbers_i++) {
for ($numbers_j = $numbers_start; $numbers_j < $numbers_end; $numbers_j++) {
if ($numbers_j >= $numbers) {
break;
}
$tbapi_num_iids_arr_sp[] = $tbapi_num_iids_arr[$numbers_j];
}
$numbers_start = $numbers_start + $numbers_max;
$numbers_end = $numbers_end + $numbers_max;
$tbapi_num_iids = implode(",", $tbapi_num_iids_arr_sp);
$c = new TopClient;
$c->appkey = 12498835; //淘宝开放平台 API 接口 App Key
$c->secretKey = "745db5f8e316f9f1aa8310a7568d6566"; //淘宝开放平台 API 接口 App Secret
$c->format = "json";
$req = new TaobaokeItemsConvertRequest;
$req->setFields("num_iid,click_url");
$req->setNumIids($tbapi_num_iids);
$req->setPid(29509662); //淘宝联盟(阿里妈妈)PID
$req->setIsMobile("true"); //如果要生成手机页面的淘宝客链接,选择 true;网页版选择 false
$resp = $c->execute($req);
$res = object2Array($resp);
if (isset($res["taobaoke_items"]["taobaoke_item"])) {
$links = $res["taobaoke_items"]["taobaoke_item"];
foreach ($links as $value) {
$memcache->set($value["num_iid"], $value["click_url"], MEMCACHE_COMPRESSED, 0);
$click_urls[(string)$value["num_iid"]] = $value["click_url"];
}
}
unset($tbapi_num_iids_arr_sp);
unset($tbapi_num_iids);
unset($resp);
unset($res);
unset($links);
unset($value);
}
}
}
foreach ($num_iids AS $num_iid) {
if (!isset($click_urls[$num_iid])) {
$memcache->set($num_iid, "", MEMCACHE_COMPRESSED, 0);
$click_urls[(string)$num_iid] = "";
}
}
$memcache->close();
return $click_urls;
}
//演示
$num_iids[] = "13583512568";
$num_iids[] = "10809380078";
$num_iids[] = "10809380079";
$click_urls = get_taobaoke_link ($num_iids);
var_dump($click_urls);
?>
require_once(dirname(__FILE__).'/TopSdk.php'); //引用淘宝开放平台 API SDK
function object2Array($d)
{
if (is_object($d))
{
$d = get_object_vars($d);
}
if (is_array($d))
{
return array_map(__FUNCTION__, $d);
}
else
{
return $d;
}
}
/*********************************************
* 函数名:get_taobaoke_link ($num_iids)
* 函数用途:通过淘宝商品 num_iids 获取其对应的淘宝客手机版链接
* 创建时间:2012-02-14
* 创建人:张宴 net@s135.com
* 参数说明:
* $num_iids 淘宝商品ID(支持多个商品)数组,示例如下:
* $num_iids[] = "13583512568";
* $num_iids[] = "10809380078";
* $num_iids[] = "10809380079";
* 返回值:
* 下标为淘宝商品 num_iid ,值为淘宝客链接 click_url 的二维数组。如果无淘宝客链接,click_url 为空字符串,示例如下:
* array(3) {
* ["13583512568"]=>
* string(191) "http://auction1.wap.taobao.com/auction/item_detail-0db2-13583512568.jhtml?tks=jUTwPLMDtUUNEZhqfEuTZqkZhGw1LA7%2BzCJBXCj27NpurHxjZN70Amg0DVaFU61pfnHwW%2FI4MZGm%0Awgb69kbb1NL8uwtu%2BDnyAunBCVDP"
* ["10809380078"]=>
* string(187) "http://auction1.wap.taobao.com/auction/item_detail-0db2-10809380078.jhtml?tks=jUTwPLMDtUUNEGWhOOgVVuX%2BJKYt7fesyuZjEe7hvmpTJxYDfK8i1Wpvfl7lwI7nzD9W8M352v6E%0AyuUtsKun81AGltKzJWCYPiVDiOeC"
* ["10809380079"]=>
* string(0) ""
* }
*********************************************/
function get_taobaoke_link ($num_iids) {
$memcache = new Memcache;
$memcache->connect('127.0.0.1', 11911); //Memcached 缓存服务器地址
$click_urls = $memcache->get($num_iids);
foreach ($num_iids AS $num_iid) {
if (!isset($click_urls[$num_iid])) {
$tbapi_num_iids_arr[] = $num_iid;
}
}
if (!empty($tbapi_num_iids_arr)) {
$numbers = count($tbapi_num_iids_arr);
$numbers_max = 40; //淘宝 API 限制最大返回40条记录
if ($numbers > 0) {
$numbers_times = ceil($numbers / $numbers_max); //第一层循环的循环次数
$numbers_start = 0;
$numbers_end = $numbers_max;
for ($numbers_i = 1; $numbers_i <= $numbers_times; $numbers_i++) {
for ($numbers_j = $numbers_start; $numbers_j < $numbers_end; $numbers_j++) {
if ($numbers_j >= $numbers) {
break;
}
$tbapi_num_iids_arr_sp[] = $tbapi_num_iids_arr[$numbers_j];
}
$numbers_start = $numbers_start + $numbers_max;
$numbers_end = $numbers_end + $numbers_max;
$tbapi_num_iids = implode(",", $tbapi_num_iids_arr_sp);
$c = new TopClient;
$c->appkey = 12498835; //淘宝开放平台 API 接口 App Key
$c->secretKey = "745db5f8e316f9f1aa8310a7568d6566"; //淘宝开放平台 API 接口 App Secret
$c->format = "json";
$req = new TaobaokeItemsConvertRequest;
$req->setFields("num_iid,click_url");
$req->setNumIids($tbapi_num_iids);
$req->setPid(29509662); //淘宝联盟(阿里妈妈)PID
$req->setIsMobile("true"); //如果要生成手机页面的淘宝客链接,选择 true;网页版选择 false
$resp = $c->execute($req);
$res = object2Array($resp);
if (isset($res["taobaoke_items"]["taobaoke_item"])) {
$links = $res["taobaoke_items"]["taobaoke_item"];
foreach ($links as $value) {
$memcache->set($value["num_iid"], $value["click_url"], MEMCACHE_COMPRESSED, 0);
$click_urls[(string)$value["num_iid"]] = $value["click_url"];
}
}
unset($tbapi_num_iids_arr_sp);
unset($tbapi_num_iids);
unset($resp);
unset($res);
unset($links);
unset($value);
}
}
}
foreach ($num_iids AS $num_iid) {
if (!isset($click_urls[$num_iid])) {
$memcache->set($num_iid, "", MEMCACHE_COMPRESSED, 0);
$click_urls[(string)$num_iid] = "";
}
}
$memcache->close();
return $click_urls;
}
//演示
$num_iids[] = "13583512568";
$num_iids[] = "10809380078";
$num_iids[] = "10809380079";
$click_urls = get_taobaoke_link ($num_iids);
var_dump($click_urls);
?>
淘宝开放平台(http://open.taobao.com/) PHP SDK 下载:
越狱的 iPhone、iPad 通过网站实现一键安装 ipa 格式的 APP 应用
[
2012-2-13 13:50 | by 张宴 ]
2012-2-13 13:50 | by 张宴 ]
1、已经越狱的 iPhone、iPad 设备,当通过其自带的 safari 浏览器访问 ipa 应用下载网站时,利用 itms-services 协议,可以一键安装 ipa 文件的 iOS 应用,例如:
2、jhsmyt.plist 的内容如下:
blog.s135.com/demo/ios/jhsmyt.plist
需要修改之处:

3、如果通过 iPhone、iPad 上的二维码扫描软件,还可以实现类似 Android 系统的扫描二维码下载 app 应用:

二维码内的网址地址为 http://blog.s135.com/demo/ios/autodown.htm 内容如下:
4、完整的 Demo 示例:
http://blog.s135.com/demo/ios/


<a href="itms-services://?action=download-manifest&url=http://blog.s135.com/demo/ios/jhsmyt.plist">通过越狱的iOS设备浏览器访问本页,点这儿一键安装APP应用。</a>
2、jhsmyt.plist 的内容如下:
blog.s135.com/demo/ios/jhsmyt.plist
需要修改之处:

3、如果通过 iPhone、iPad 上的二维码扫描软件,还可以实现类似 Android 系统的扫描二维码下载 app 应用:

二维码内的网址地址为 http://blog.s135.com/demo/ios/autodown.htm 内容如下:
4、完整的 Demo 示例:
http://blog.s135.com/demo/ios/


PHP-CGI 进程 CPU 100% 与 file_get_contents 函数的关系
[
2011-8-5 15:33 | by 张宴 ]
2011-8-5 15:33 | by 张宴 ]
[文章作者:张宴 本文版本:v1.0 最后修改:2011.08.05 转载请注明原文链接:http://blog.s135.com/file_get_contents/]
有时候,运行 Nginx、PHP-CGI(php-fpm) Web服务的 Linux 服务器,突然系统负载上升,使用 top 命令查看,很多 php-cgi 进程 CPU 使用率接近100%。后来,我通过跟踪发现,这类情况的出现,跟 PHP 的 file_get_contents() 函数有着密切的关系。
大、中型网站中,基于 HTTP 协议的 API 接口调用,是家常便饭。PHP 程序员们喜欢使用简单便捷的 file_get_contents("http://example.com/") 函数,来获取一个 URL 的返回内容,但是,如果 http://example.com/ 这个网站响应缓慢,file_get_contents() 就会一直卡在那儿,不会超时。
我们知道,在 php.ini 中,有一个参数 max_execution_time 可以设置 PHP 脚本的最大执行时间,但是,在 php-cgi(php-fpm) 中,该参数不会起效。真正能够控制 PHP 脚本最大执行时间的是 php-fpm.conf 配置文件中的以下参数:
默认值为 0 秒,也就是说,PHP 脚本会一直执行下去。这样,当所有的 php-cgi 进程都卡在 file_get_contents() 函数时,这台 Nginx+PHP 的 WebServer 已经无法再处理新的 PHP 请求了,Nginx 将给用户返回“502 Bad Gateway”。修改该参数,设置一个 PHP 脚本最大执行时间是必要的,但是,治标不治本。例如改成 <value name="request_terminate_timeout">30s</value>,如果发生 file_get_contents() 获取网页内容较慢的情况,这就意味着 150 个 php-cgi 进程,每秒钟只能处理 5 个请求,WebServer 同样很难避免“502 Bad Gateway”。
要做到彻底解决,只能让 PHP 程序员们改掉直接使用 file_get_contents("http://example.com/") 的习惯,而是稍微修改一下,加个超时时间,用以下方式来实现 HTTP GET 请求。要是觉得麻烦,可以自行将以下代码封装成一个函数。
当然,导致 php-cgi 进程 CPU 100% 的原因不只有这一种,那么,怎么确定是 file_get_contents() 函数导致的呢?
首先,使用 top 命令查看 CPU 使用率较高的 php-cgi 进程。
找其中一个 CPU 100% 的 php-cgi 进程的 PID,用以下命令跟踪一下:
如果屏幕显示:
那么,就可以确定是 file_get_contents() 导致的问题了。
有时候,运行 Nginx、PHP-CGI(php-fpm) Web服务的 Linux 服务器,突然系统负载上升,使用 top 命令查看,很多 php-cgi 进程 CPU 使用率接近100%。后来,我通过跟踪发现,这类情况的出现,跟 PHP 的 file_get_contents() 函数有着密切的关系。
大、中型网站中,基于 HTTP 协议的 API 接口调用,是家常便饭。PHP 程序员们喜欢使用简单便捷的 file_get_contents("http://example.com/") 函数,来获取一个 URL 的返回内容,但是,如果 http://example.com/ 这个网站响应缓慢,file_get_contents() 就会一直卡在那儿,不会超时。
我们知道,在 php.ini 中,有一个参数 max_execution_time 可以设置 PHP 脚本的最大执行时间,但是,在 php-cgi(php-fpm) 中,该参数不会起效。真正能够控制 PHP 脚本最大执行时间的是 php-fpm.conf 配置文件中的以下参数:
默认值为 0 秒,也就是说,PHP 脚本会一直执行下去。这样,当所有的 php-cgi 进程都卡在 file_get_contents() 函数时,这台 Nginx+PHP 的 WebServer 已经无法再处理新的 PHP 请求了,Nginx 将给用户返回“502 Bad Gateway”。修改该参数,设置一个 PHP 脚本最大执行时间是必要的,但是,治标不治本。例如改成 <value name="request_terminate_timeout">30s</value>,如果发生 file_get_contents() 获取网页内容较慢的情况,这就意味着 150 个 php-cgi 进程,每秒钟只能处理 5 个请求,WebServer 同样很难避免“502 Bad Gateway”。
要做到彻底解决,只能让 PHP 程序员们改掉直接使用 file_get_contents("http://example.com/") 的习惯,而是稍微修改一下,加个超时时间,用以下方式来实现 HTTP GET 请求。要是觉得麻烦,可以自行将以下代码封装成一个函数。
当然,导致 php-cgi 进程 CPU 100% 的原因不只有这一种,那么,怎么确定是 file_get_contents() 函数导致的呢?
首先,使用 top 命令查看 CPU 使用率较高的 php-cgi 进程。
top - 10:34:18 up 724 days, 21:01, 3 users, load average: 17.86, 11.16, 7.69
Tasks: 561 total, 15 running, 546 sleeping, 0 stopped, 0 zombie
Cpu(s): 5.9%us, 4.2%sy, 0.0%ni, 89.4%id, 0.2%wa, 0.0%hi, 0.2%si, 0.0%st
Mem: 8100996k total, 4320108k used, 3780888k free, 772572k buffers
Swap: 8193108k total, 50776k used, 8142332k free, 412088k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
10747 www 18 0 360m 22m 12m R 100.6 0.3 0:02.60 php-cgi
10709 www 16 0 359m 28m 17m R 96.8 0.4 0:11.34 php-cgi
10745 www 18 0 360m 24m 14m R 94.8 0.3 0:39.51 php-cgi
10707 www 18 0 360m 25m 14m S 77.4 0.3 0:33.48 php-cgi
10782 www 20 0 360m 26m 15m R 75.5 0.3 0:10.93 php-cgi
10708 www 25 0 360m 22m 12m R 69.7 0.3 0:45.16 php-cgi
10683 www 25 0 362m 28m 15m R 54.2 0.4 0:32.65 php-cgi
10711 www 25 0 360m 25m 15m R 52.2 0.3 0:44.25 php-cgi
10688 www 25 0 359m 25m 15m R 38.7 0.3 0:10.44 php-cgi
10719 www 25 0 360m 26m 16m R 7.7 0.3 0:40.59 php-cgi
Tasks: 561 total, 15 running, 546 sleeping, 0 stopped, 0 zombie
Cpu(s): 5.9%us, 4.2%sy, 0.0%ni, 89.4%id, 0.2%wa, 0.0%hi, 0.2%si, 0.0%st
Mem: 8100996k total, 4320108k used, 3780888k free, 772572k buffers
Swap: 8193108k total, 50776k used, 8142332k free, 412088k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
10747 www 18 0 360m 22m 12m R 100.6 0.3 0:02.60 php-cgi
10709 www 16 0 359m 28m 17m R 96.8 0.4 0:11.34 php-cgi
10745 www 18 0 360m 24m 14m R 94.8 0.3 0:39.51 php-cgi
10707 www 18 0 360m 25m 14m S 77.4 0.3 0:33.48 php-cgi
10782 www 20 0 360m 26m 15m R 75.5 0.3 0:10.93 php-cgi
10708 www 25 0 360m 22m 12m R 69.7 0.3 0:45.16 php-cgi
10683 www 25 0 362m 28m 15m R 54.2 0.4 0:32.65 php-cgi
10711 www 25 0 360m 25m 15m R 52.2 0.3 0:44.25 php-cgi
10688 www 25 0 359m 25m 15m R 38.7 0.3 0:10.44 php-cgi
10719 www 25 0 360m 26m 16m R 7.7 0.3 0:40.59 php-cgi
找其中一个 CPU 100% 的 php-cgi 进程的 PID,用以下命令跟踪一下:
strace -p 10747
如果屏幕显示:
select(7, [6], [6], [], {15, 0}) = 1 (out [6], left {15, 0})
poll([{fd=6, events=POLLIN}], 1, 0) = 0 (Timeout)
select(7, [6], [6], [], {15, 0}) = 1 (out [6], left {15, 0})
poll([{fd=6, events=POLLIN}], 1, 0) = 0 (Timeout)
select(7, [6], [6], [], {15, 0}) = 1 (out [6], left {15, 0})
poll([{fd=6, events=POLLIN}], 1, 0) = 0 (Timeout)
select(7, [6], [6], [], {15, 0}) = 1 (out [6], left {15, 0})
poll([{fd=6, events=POLLIN}], 1, 0) = 0 (Timeout)
select(7, [6], [6], [], {15, 0}) = 1 (out [6], left {15, 0})
poll([{fd=6, events=POLLIN}], 1, 0) = 0 (Timeout)
select(7, [6], [6], [], {15, 0}) = 1 (out [6], left {15, 0})
poll([{fd=6, events=POLLIN}], 1, 0) = 0 (Timeout)
select(7, [6], [6], [], {15, 0}) = 1 (out [6], left {15, 0})
poll([{fd=6, events=POLLIN}], 1, 0) = 0 (Timeout)
select(7, [6], [6], [], {15, 0}) = 1 (out [6], left {15, 0})
poll([{fd=6, events=POLLIN}], 1, 0) = 0 (Timeout)
select(7, [6], [6], [], {15, 0}) = 1 (out [6], left {15, 0})
poll([{fd=6, events=POLLIN}], 1, 0) = 0 (Timeout)
select(7, [6], [6], [], {15, 0}) = 1 (out [6], left {15, 0})
poll([{fd=6, events=POLLIN}], 1, 0) = 0 (Timeout)
poll([{fd=6, events=POLLIN}], 1, 0) = 0 (Timeout)
select(7, [6], [6], [], {15, 0}) = 1 (out [6], left {15, 0})
poll([{fd=6, events=POLLIN}], 1, 0) = 0 (Timeout)
select(7, [6], [6], [], {15, 0}) = 1 (out [6], left {15, 0})
poll([{fd=6, events=POLLIN}], 1, 0) = 0 (Timeout)
select(7, [6], [6], [], {15, 0}) = 1 (out [6], left {15, 0})
poll([{fd=6, events=POLLIN}], 1, 0) = 0 (Timeout)
select(7, [6], [6], [], {15, 0}) = 1 (out [6], left {15, 0})
poll([{fd=6, events=POLLIN}], 1, 0) = 0 (Timeout)
select(7, [6], [6], [], {15, 0}) = 1 (out [6], left {15, 0})
poll([{fd=6, events=POLLIN}], 1, 0) = 0 (Timeout)
select(7, [6], [6], [], {15, 0}) = 1 (out [6], left {15, 0})
poll([{fd=6, events=POLLIN}], 1, 0) = 0 (Timeout)
select(7, [6], [6], [], {15, 0}) = 1 (out [6], left {15, 0})
poll([{fd=6, events=POLLIN}], 1, 0) = 0 (Timeout)
select(7, [6], [6], [], {15, 0}) = 1 (out [6], left {15, 0})
poll([{fd=6, events=POLLIN}], 1, 0) = 0 (Timeout)
select(7, [6], [6], [], {15, 0}) = 1 (out [6], left {15, 0})
poll([{fd=6, events=POLLIN}], 1, 0) = 0 (Timeout)
那么,就可以确定是 file_get_contents() 导致的问题了。
HTTPSQS 1.7 发布:Libevent 2.0.x 的 evhttp_parse_query BUG 与动态编译时指定动态链接库 .so 寻找路径
[
2011-7-26 17:07 | by 张宴 ]
2011-7-26 17:07 | by 张宴 ]
[文章作者:张宴 本文版本:v1.0 最后修改:2011.07.26 转载请注明原文链接:http://blog.s135.com/httpsqs_1_7/]
HTTPSQS(HTTP Simple Queue Service)是一款基于 HTTP GET/POST 协议的轻量级开源简单消息队列服务,使用 Tokyo Cabinet 的 B+Tree Key/Value 数据库来做数据的持久化存储。
项目网址:http://code.google.com/p/httpsqs/
使用文档:http://blog.s135.com/httpsqs/
使用环境:Linux(同时支持32位、64位操作系统,推荐使用64位操作系统)
软件作者:张宴
HTTPSQS 1.7 版本更新内容:
下面的内容不只是介绍 HTTPSQS 1.7 更新了哪些东西,更多的介绍在于:如何绕开 Libevent 2.0.x evhttp 使用过程中,无法正常处理包含“|”字符的 URI 参数的问题;提供了一份比 Libevent 官方网站更新的在线文档;Linux 下如何动态编译程序,运行时不用在 /etc/ld.so.conf 文件中添加动态链接库路径。
1、针对 Libevent 2.0.x 版本 evhttp_parse_query 函数的 BUG。
网友发邮件,反应了一个 HTTPSQS 的 BUG,见下图,data 的值为NULL。我查找发现,这不是 HTTPSQS 的 BUG,而是 Libevent 2.0.x 版本的 BUG。在 Libevent 1.4.14b 版本中,evhttp_parse_query 函数是能够正常处理包含“|”字符的 URI 的,而在 Libevent 2.0.12 版本中,同样使用 evhttp_parse_query 函数,包含“|”字符的 URI 处理后的结果是 NULL。

对比 Libevent 2.0.12 和 1.4.14b 版本的 evhttp_parse_query 函数代码,发现在 2.0.12 版本中,evhttp_parse_query(const char *uri, struct evkeyvalq *headers) 实际变成了调用 evhttp_parse_query_impl(uri, headers, 1) 函数,该函数内再调用的一个 2.0.x 版本新增的函数 evhttp_uri_parse(const char *source_uri),逻辑处理代码在 evhttp_uri_parse_with_flags(const char *source_uri, unsigned flags) 函数中。evhttp_uri_parse(const char *source_uri) 无法正确解析含有“|”的URL,遇到类似“http://127.0.0.1:1218/?opt=get&name=aaa|bbb”的URL,直接返回NULL,也就是 BUG 所在。
libevent-2.0.12-stable/http.c



不建议修改第三方库,这个 BUG 还是留给 Libevent 自己去解决吧。使用 Libevent 2.0.x evhttp 作开发的同学,遇到URI参数中包含“|”的问题,注意一下吧。
我修改了 HTTPSQS 代码,在 HTTPSQS 1.7 版本,采用以下方式来绕开evhttp_uri_parse(const char *source_uri)函数,解决这个问题。其中用到了 Libevent 2.0.x evhttp_request 结构体中新增的 struct evhttp_uri *uri_elems,以及新增的函数 evhttp_parse_query_str (const char *uri, struct evkeyvalq *headers)。
Libevent 的官方文档只有 1.4.10-stable 和 2.0.1-alpha 版本的,2.0.1x 很多新增的函数、结构体都没有。
我这里提供一份最新的 Libevent 在线文档: http://blog.s135.com/book/libevent/
2、静态编译改为动态编译,并指定程序运行时查找的动态链接库路径
一些网友反映,CentOS 6.0、Fedora 等系统没有默认安装lz、lbz2、lrt、...等静态链接库,出现无法编译HTTPSQS的情况:
HTTPSQS 1.7 版本改为动态编译,编译时使用“-Wl,-rpath”参数指定了程序运行时的动态库搜索路径。这样就不需要在 /etc/ld.so.conf 中 添加 HTTPSQS 程序运行时需要的 libevent、tokyocabinet 动态链接库路径了,可以避免与其他软件(例如:Memcached、TT)使用的 libevent、tokyocabinet 动态链接库版本相冲突。详情请见 Makefile 文件:
HTTPSQS(HTTP Simple Queue Service)是一款基于 HTTP GET/POST 协议的轻量级开源简单消息队列服务,使用 Tokyo Cabinet 的 B+Tree Key/Value 数据库来做数据的持久化存储。
项目网址:http://code.google.com/p/httpsqs/
使用文档:http://blog.s135.com/httpsqs/
使用环境:Linux(同时支持32位、64位操作系统,推荐使用64位操作系统)
软件作者:张宴
HTTPSQS 1.7 版本更新内容:
下面的内容不只是介绍 HTTPSQS 1.7 更新了哪些东西,更多的介绍在于:如何绕开 Libevent 2.0.x evhttp 使用过程中,无法正常处理包含“|”字符的 URI 参数的问题;提供了一份比 Libevent 官方网站更新的在线文档;Linux 下如何动态编译程序,运行时不用在 /etc/ld.so.conf 文件中添加动态链接库路径。
1、针对 Libevent 2.0.x 版本 evhttp_parse_query 函数的 BUG。
网友发邮件,反应了一个 HTTPSQS 的 BUG,见下图,data 的值为NULL。我查找发现,这不是 HTTPSQS 的 BUG,而是 Libevent 2.0.x 版本的 BUG。在 Libevent 1.4.14b 版本中,evhttp_parse_query 函数是能够正常处理包含“|”字符的 URI 的,而在 Libevent 2.0.12 版本中,同样使用 evhttp_parse_query 函数,包含“|”字符的 URI 处理后的结果是 NULL。

对比 Libevent 2.0.12 和 1.4.14b 版本的 evhttp_parse_query 函数代码,发现在 2.0.12 版本中,evhttp_parse_query(const char *uri, struct evkeyvalq *headers) 实际变成了调用 evhttp_parse_query_impl(uri, headers, 1) 函数,该函数内再调用的一个 2.0.x 版本新增的函数 evhttp_uri_parse(const char *source_uri),逻辑处理代码在 evhttp_uri_parse_with_flags(const char *source_uri, unsigned flags) 函数中。evhttp_uri_parse(const char *source_uri) 无法正确解析含有“|”的URL,遇到类似“http://127.0.0.1:1218/?opt=get&name=aaa|bbb”的URL,直接返回NULL,也就是 BUG 所在。
libevent-2.0.12-stable/http.c



不建议修改第三方库,这个 BUG 还是留给 Libevent 自己去解决吧。使用 Libevent 2.0.x evhttp 作开发的同学,遇到URI参数中包含“|”的问题,注意一下吧。
我修改了 HTTPSQS 代码,在 HTTPSQS 1.7 版本,采用以下方式来绕开evhttp_uri_parse(const char *source_uri)函数,解决这个问题。其中用到了 Libevent 2.0.x evhttp_request 结构体中新增的 struct evhttp_uri *uri_elems,以及新增的函数 evhttp_parse_query_str (const char *uri, struct evkeyvalq *headers)。
Libevent 的官方文档只有 1.4.10-stable 和 2.0.1-alpha 版本的,2.0.1x 很多新增的函数、结构体都没有。
我这里提供一份最新的 Libevent 在线文档: http://blog.s135.com/book/libevent/
2、静态编译改为动态编译,并指定程序运行时查找的动态链接库路径
一些网友反映,CentOS 6.0、Fedora 等系统没有默认安装lz、lbz2、lrt、...等静态链接库,出现无法编译HTTPSQS的情况:
gcc -o httpsqs httpsqs.c prename.c -L/usr/local/libevent-2.0.10-stable/lib/ -levent -L/usr/local/tokyocabinet-1.4.47/lib/ -ltokyocabinet -I/usr/local/libevent-2.0.10-stable/include/ -I/usr/local/tokyocabinet-1.4.47/include/ -lz -lbz2 -lrt -lpthread -lm -lc -O2 -g --static
/usr/bin/ld: cannot find -lz
/usr/bin/ld: cannot find -lbz2
/usr/bin/ld: cannot find -lrt
/usr/bin/ld: cannot find -lpthread
/usr/bin/ld: cannot find -lm
/usr/bin/ld: cannot find -lc
/usr/bin/ld: cannot find -lc
collect2: ld 返回 1
make: *** [httpsqs] 错误 1
/usr/bin/ld: cannot find -lz
/usr/bin/ld: cannot find -lbz2
/usr/bin/ld: cannot find -lrt
/usr/bin/ld: cannot find -lpthread
/usr/bin/ld: cannot find -lm
/usr/bin/ld: cannot find -lc
/usr/bin/ld: cannot find -lc
collect2: ld 返回 1
make: *** [httpsqs] 错误 1
HTTPSQS 1.7 版本改为动态编译,编译时使用“-Wl,-rpath”参数指定了程序运行时的动态库搜索路径。这样就不需要在 /etc/ld.so.conf 中 添加 HTTPSQS 程序运行时需要的 libevent、tokyocabinet 动态链接库路径了,可以避免与其他软件(例如:Memcached、TT)使用的 libevent、tokyocabinet 动态链接库版本相冲突。详情请见 Makefile 文件:
# Makefile for httpsqs
CC=gcc
CFLAGS=-Wl,-rpath,/usr/local/libevent-2.0.12-stable/lib/:/usr/local/tokyocabinet-1.4.47/lib/ -L/usr/local/libevent-2.0.12-stable/lib/ -levent -L/usr/local/tokyocabinet-1.4.47/lib/ -ltokyocabinet -I/usr/local/libevent-2.0.12-stable/include/ -I/usr/local/tokyocabinet-1.4.47/include/ -lz -lbz2 -lrt -lpthread -lm -lc -O2 -g
httpsqs: httpsqs.c
$(CC) -o httpsqs httpsqs.c prename.c $(CFLAGS)
@echo ""
@echo "httpsqs build complete."
@echo ""
clean: httpsqs
rm -f httpsqs
install: httpsqs
install $(INSTALL_FLAGS) -m 4755 -o root httpsqs $(DESTDIR)/usr/bin
CC=gcc
CFLAGS=-Wl,-rpath,/usr/local/libevent-2.0.12-stable/lib/:/usr/local/tokyocabinet-1.4.47/lib/ -L/usr/local/libevent-2.0.12-stable/lib/ -levent -L/usr/local/tokyocabinet-1.4.47/lib/ -ltokyocabinet -I/usr/local/libevent-2.0.12-stable/include/ -I/usr/local/tokyocabinet-1.4.47/include/ -lz -lbz2 -lrt -lpthread -lm -lc -O2 -g
httpsqs: httpsqs.c
$(CC) -o httpsqs httpsqs.c prename.c $(CFLAGS)
@echo ""
@echo "httpsqs build complete."
@echo ""
clean: httpsqs
rm -f httpsqs
install: httpsqs
install $(INSTALL_FLAGS) -m 4755 -o root httpsqs $(DESTDIR)/usr/bin
2011年夏,木兰围场与乌兰布统大草原三日游
[
2011-7-12 17:17 | by 张宴 ]
2011-7-12 17:17 | by 张宴 ]
2011年7月8日早上7:00,作为领队,带领金山游戏运营技术中心部分同事、家属组成的45人旅行团,乘大巴车从北京金山软件大厦出发,开始承德木兰围场、内蒙古乌兰布统大草原三日游。
没有去过的朋友,可以将本文当成一篇攻略;无论是否去过的朋友,都可以将本文当成一篇美景欣赏相册。木兰围场、乌兰布统大草原,真是太漂亮了。
【第一天:2011年7月8日】
“北京→木兰围场”行车路线:
Flash Player文件
【万顷林海】
经过3个小时的京承高速、3个小时的国道,到达“塞罕坝国家森林公园”山门。
车过山门,还需1小时的山路,观千里松林、万顷林海。53座的大巴车,挑战360度的下坡大转弯,还是有些难度的。

没有去过的朋友,可以将本文当成一篇攻略;无论是否去过的朋友,都可以将本文当成一篇美景欣赏相册。木兰围场、乌兰布统大草原,真是太漂亮了。
【第一天:2011年7月8日】
“北京→木兰围场”行车路线:
Flash Player文件【万顷林海】
经过3个小时的京承高速、3个小时的国道,到达“塞罕坝国家森林公园”山门。
车过山门,还需1小时的山路,观千里松林、万顷林海。53座的大巴车,挑战360度的下坡大转弯,还是有些难度的。
Windows 服务程序、窗口界面与远程桌面的那点事
[
2011-6-28 17:17 | by 张宴 ]
2011-6-28 17:17 | by 张宴 ]
[文章作者:张宴 本文版本:v1.0 最后修改:2011.06.28 转载请注明原文链接:http://blog.s135.com/windows_mstsc/]
个人不喜欢服务端程序,以 Windows 操作系统作为运行平台,但是,很多时候,迫于环境现状,需要让自己的程序实现跨平台。
在开发全新的金山游戏运营平台时,发现:虽然大部分游戏,服务端程序运行在 Linux 服务器,但是,仍有例外。几款最近代理的游戏,服务端运行在 Windows 服务器上。西山居开发的游戏,服务端集群架构,既有 Windows 服务器,又有 Linux 服务器。

游戏运行系统的 Knose 程序,我最初是在 Linux 下开发的,后来才实现了兼容 Windows 的跨平台版本。

在 Linux 下,Knose 为“父子进程+指令处理线程池+独立功能多线程”结构;在 Windows 上,将 Knose 父子进程结构,拆分成了 knose_daemon.exe(Service 服务程序)和 knose.exe(主程序),由 knose_daemon.exe 启动 knose.exe。

遇到了问题:按照运营维护需求,knose.exe 以及通过它启动的游戏服务端进程,需要有“窗口界面”,显示在桌面中。而 knose_daemon.exe 是以服务方式运行的,无窗口界面,knose_daemon.exe 启动的 knose.exe,窗口界面没有弹出来。
为了解决这个问题,我在 install.bat 中,用了 Windows 的 sc 命令,将 knose_daemon.exe 启动为系统服务,“type= interact type= own”设置了“允许桌面与服务交互”。在本机(Windows XP SP3)测试,knose.exe 的窗口界面以及通过它启动的游戏进程窗口界面,都弹出来了。

于是将程序发布到 Windows Server 2003 服务器上,远程桌面连接上去,发现 knose.exe 的窗口界面始终弹不出来。
后来,同事发现,原来是“远程桌面”惹的祸:
远程桌面客户端 mstsc 有一个 /console 参数,模式等同于本地终端显示器登录,/console 不会去占用非 /console 远程桌面,远程桌面允许两个正常连接和一个控制台/console方式连接,并且正常连接和 /console 连接的桌面操作不能相互看见,只有通过 /console 参数远程桌面连接到 Windows 2003 服务器,才能够看到弹出的 knose.exe 窗口界面。
在 Windows XP SP3 以上版本,/console 参数改名为 /admin,需要用 mstsc /admin 启动远程桌面:

连上后,终于能够看到由 knose_daemon.exe 启动的 knose.exe 程序窗口,以及由 knose.exe 启动的游戏服务端进程窗口了。
个人不喜欢服务端程序,以 Windows 操作系统作为运行平台,但是,很多时候,迫于环境现状,需要让自己的程序实现跨平台。
在开发全新的金山游戏运营平台时,发现:虽然大部分游戏,服务端程序运行在 Linux 服务器,但是,仍有例外。几款最近代理的游戏,服务端运行在 Windows 服务器上。西山居开发的游戏,服务端集群架构,既有 Windows 服务器,又有 Linux 服务器。

游戏运行系统的 Knose 程序,我最初是在 Linux 下开发的,后来才实现了兼容 Windows 的跨平台版本。

在 Linux 下,Knose 为“父子进程+指令处理线程池+独立功能多线程”结构;在 Windows 上,将 Knose 父子进程结构,拆分成了 knose_daemon.exe(Service 服务程序)和 knose.exe(主程序),由 knose_daemon.exe 启动 knose.exe。

遇到了问题:按照运营维护需求,knose.exe 以及通过它启动的游戏服务端进程,需要有“窗口界面”,显示在桌面中。而 knose_daemon.exe 是以服务方式运行的,无窗口界面,knose_daemon.exe 启动的 knose.exe,窗口界面没有弹出来。
为了解决这个问题,我在 install.bat 中,用了 Windows 的 sc 命令,将 knose_daemon.exe 启动为系统服务,“type= interact type= own”设置了“允许桌面与服务交互”。在本机(Windows XP SP3)测试,knose.exe 的窗口界面以及通过它启动的游戏进程窗口界面,都弹出来了。
@echo off
sc create "KingeyesKnose" binPath= "%CD%\knose_daemon.exe" DisplayName= "Kingeyes Knose Daemon" start= auto type= interact type= own
sc description KingeyesKnose "金山游戏运营系统 KingEyes Knose 守护进程。"
sc start KingeyesKnose
sc create "KingeyesKnose" binPath= "%CD%\knose_daemon.exe" DisplayName= "Kingeyes Knose Daemon" start= auto type= interact type= own
sc description KingeyesKnose "金山游戏运营系统 KingEyes Knose 守护进程。"
sc start KingeyesKnose

于是将程序发布到 Windows Server 2003 服务器上,远程桌面连接上去,发现 knose.exe 的窗口界面始终弹不出来。
后来,同事发现,原来是“远程桌面”惹的祸:
远程桌面客户端 mstsc 有一个 /console 参数,模式等同于本地终端显示器登录,/console 不会去占用非 /console 远程桌面,远程桌面允许两个正常连接和一个控制台/console方式连接,并且正常连接和 /console 连接的桌面操作不能相互看见,只有通过 /console 参数远程桌面连接到 Windows 2003 服务器,才能够看到弹出的 knose.exe 窗口界面。
在 Windows XP SP3 以上版本,/console 参数改名为 /admin,需要用 mstsc /admin 启动远程桌面:

连上后,终于能够看到由 knose_daemon.exe 启动的 knose.exe 程序窗口,以及由 knose.exe 启动的游戏服务端进程窗口了。
2011中国PHP技术高峰论坛:PHP在金山游戏运营中的应用
[
2011-5-8 19:40 | by 张宴 ]
2011-5-8 19:40 | by 张宴 ]
5月7日,我在北京长城饭店“2011中国PHP技术高峰论坛”上的演讲PPT:
下载地址1(国外服务器):http://blog.s135.com/attachment/201105/2011phptc_zy.zip
下载地址2(国内服务器):http://ishare.iask.sina.com.cn/f/15231659.html

以下是我在会议主办方对演讲文字速录的基础上,修正错漏内容,整理之后,对应到每页PPT的文字内容:
[PPT No.1]
大家下午好,现在我来跟大家分享的是PHP在金山游戏运营中的应用,包括团队协助开发实现方式、网站Web架构设计、游戏运营平台设计这些信息。
[PPT No.2]
我议题主要有两个,一个是金山游戏官方网站的一些应用,另一个是金山游戏运营系统Keyes中的架构设计。
[PPT No.3]
金山游戏官方网站包括用户中心、客服系统、论坛、视频、各游戏官网,以及其他跟游戏相关的一些产品,主要采用64位CentOS Linux系统、Nginx、PHP 5.2版本、MySQL 5.5。
[PPT No.4]
首先来看团队协作开发。我们肯定遇到过这样一种情况,在很多项目中,都是多个人同时开发,涉及到开发环境和测试环境不一样。我们很多PHP工程师,都是在Windows上开发代码,虽然Windows上也可以配置Nginx+PHP+MySQL环境,但是,由于测试环境、生产环境都是Linux系统,而且一些功能只能在Linux下运行,还有一些PHP扩展(例如:分布式图片处理、金山通行证加密扩展),也只能运行在Linux环境中。当我们在Windows上修改完几行PHP代码,想马上看一下执行结果,如果利用FTP之类的工具传到Linux测试服务器上再测试,就太慢了。如果同一台Linux测试服务器上,有多少人同时开发,你上传上去PHP文件,可能会覆盖别人上传的同名文件,就没有办法做到版本控制。
[PPT No.5]
我们从图中可以看到,假如是程序员A和B都在Windows上开发代码,由于Nginx与PHP之间采用的是TCP FastCGI协议通讯,因此,两者可以分离到不同的服务器上。我们可以把Nginx安装在程序员各自的Windows PC机上,用本机的Nginx处理HTTP请求,用Linux测试服务器上的php-cgi程序,处理PHP请求。程序员在Windows上开发程序,保存之后,不用做任何上传操作,即可用Linux上的php-cgi调试程序。从图中这个流程可以看到,首先,两个程序员分别从SVN版本库,获取到一个项目的最新版本,各自进行一些修改。两人修改程序时,采用的是同一台Linux测试服务器的php-cgi,对各自PC机上的PHP程序进行调试。在PC机上本地测试没有问题,可以提交到SVN版本库。我们做了一个自动同步程序,利用SVN钩子,在每次发生svn commit提交时,在对应的测试服务器的对应项目路径内,执行svn update,将最新修改到文件同步到测试服务器。后来发现有一些问题,如果我们一个项目的目录、程序文件特别多的话,svn update需要遍历扫描目录列表,非常慢。因为我们的SVN是和Apache结合起来使用的,Apache可以记录日志,于是,我们进行了改进,将SVN提交日志记录到Linux下的命名管道内,再用一个程序从命名管道内读取日志,只svn update每次修改的几个文件,这样,速度就非常快了。设置hosts为Linux测试服务器的IP,就可以测试多位程序员代码合并后的效果了。
下载地址1(国外服务器):http://blog.s135.com/attachment/201105/2011phptc_zy.zip
下载地址2(国内服务器):http://ishare.iask.sina.com.cn/f/15231659.html

以下是我在会议主办方对演讲文字速录的基础上,修正错漏内容,整理之后,对应到每页PPT的文字内容:
[PPT No.1]
大家下午好,现在我来跟大家分享的是PHP在金山游戏运营中的应用,包括团队协助开发实现方式、网站Web架构设计、游戏运营平台设计这些信息。
[PPT No.2]
我议题主要有两个,一个是金山游戏官方网站的一些应用,另一个是金山游戏运营系统Keyes中的架构设计。
[PPT No.3]
金山游戏官方网站包括用户中心、客服系统、论坛、视频、各游戏官网,以及其他跟游戏相关的一些产品,主要采用64位CentOS Linux系统、Nginx、PHP 5.2版本、MySQL 5.5。
[PPT No.4]
首先来看团队协作开发。我们肯定遇到过这样一种情况,在很多项目中,都是多个人同时开发,涉及到开发环境和测试环境不一样。我们很多PHP工程师,都是在Windows上开发代码,虽然Windows上也可以配置Nginx+PHP+MySQL环境,但是,由于测试环境、生产环境都是Linux系统,而且一些功能只能在Linux下运行,还有一些PHP扩展(例如:分布式图片处理、金山通行证加密扩展),也只能运行在Linux环境中。当我们在Windows上修改完几行PHP代码,想马上看一下执行结果,如果利用FTP之类的工具传到Linux测试服务器上再测试,就太慢了。如果同一台Linux测试服务器上,有多少人同时开发,你上传上去PHP文件,可能会覆盖别人上传的同名文件,就没有办法做到版本控制。
[PPT No.5]
我们从图中可以看到,假如是程序员A和B都在Windows上开发代码,由于Nginx与PHP之间采用的是TCP FastCGI协议通讯,因此,两者可以分离到不同的服务器上。我们可以把Nginx安装在程序员各自的Windows PC机上,用本机的Nginx处理HTTP请求,用Linux测试服务器上的php-cgi程序,处理PHP请求。程序员在Windows上开发程序,保存之后,不用做任何上传操作,即可用Linux上的php-cgi调试程序。从图中这个流程可以看到,首先,两个程序员分别从SVN版本库,获取到一个项目的最新版本,各自进行一些修改。两人修改程序时,采用的是同一台Linux测试服务器的php-cgi,对各自PC机上的PHP程序进行调试。在PC机上本地测试没有问题,可以提交到SVN版本库。我们做了一个自动同步程序,利用SVN钩子,在每次发生svn commit提交时,在对应的测试服务器的对应项目路径内,执行svn update,将最新修改到文件同步到测试服务器。后来发现有一些问题,如果我们一个项目的目录、程序文件特别多的话,svn update需要遍历扫描目录列表,非常慢。因为我们的SVN是和Apache结合起来使用的,Apache可以记录日志,于是,我们进行了改进,将SVN提交日志记录到Linux下的命名管道内,再用一个程序从命名管道内读取日志,只svn update每次修改的几个文件,这样,速度就非常快了。设置hosts为Linux测试服务器的IP,就可以测试多位程序员代码合并后的效果了。
轻量级开源简单队列服务 HTTPSQS 1.6 版本发布
[
2011-4-21 18:12 | by 张宴 ]
2011-4-21 18:12 | by 张宴 ]
[文章作者:张宴 本文版本:v1.0 最后修改:2011.04.21 转载请注明原文链接:http://blog.s135.com/httpsqs_1_6/]
HTTPSQS(HTTP Simple Queue Service)是一款基于 HTTP GET/POST 协议的轻量级开源简单消息队列服务,使用 Tokyo Cabinet 的 B+Tree Key/Value 数据库来做数据的持久化存储。
项目网址:http://code.google.com/p/httpsqs/
使用文档:http://blog.s135.com/httpsqs/
使用环境:Linux(同时支持32位、64位操作系统,推荐使用64位操作系统)
软件作者:张宴
队列(Queue)又称先进先出表(First In First Out),即先进入队列的元素,先从队列中取出。加入元素的一头叫“队头”,取出元素的一头叫“队尾”。利用消息队列可以很好地异步处理数据传送和存储,当你频繁地向数据库中插入数据、频繁地向搜索引擎提交数据,就可采取消息队列来异步插入。另外,还可以将较慢的处理逻辑、有并发数量限制的处理逻辑,通过消息队列放在后台处理,例如FLV视频转换、发送手机短信、发送电子邮件等。
HTTPSQS 具有以下特征:
● 非常简单,基于 HTTP GET/POST 协议。PHP、Java、Perl、Shell、Python、Ruby等支持HTTP协议的编程语言均可调用。
● 非常快速,入队列、出队列速度超过10000次/秒。
● 高并发,支持上万的并发连接,C10K不成问题。
● 支持多队列。
● 单个队列支持的最大队列数量高达10亿条。
● 低内存消耗,海量数据存储,存储几十GB的数据只需不到100MB的物理内存缓冲区。
● 可以在不停止服务的情况下便捷地修改单个队列的最大队列数量。
● 可以实时查看队列状态(入队列位置、出队列位置、未读队列数量、最大队列数量)。
● 可以查看指定队列ID(队列点)的内容,包括未出、已出的队列内容。
● 查看队列内容时,支持多字符集编码。
● 源代码不超过800行,适合二次开发。
HTTPSQS 1.6 版本更新内容:
一、服务器端:
1、修正了定时将内存缓冲区内容同步到磁盘,有时候出现段错误,导致进程崩溃的BUG。感谢以下网友的反馈:



2、修正了判断队列已满,遗漏的一种情况。感谢以下网友的反馈:


3、改为父子进程模式,生产环境稳定性更高。
4、改进了 ps 命令查看 httpsqs 的用户体验:

5、增加了密码校验功能(通过以下启动参数设置密码,通过URL参数“/?auth=密码”访问):

6、改为静态编译,编译完成后的 HTTPSQS 二进制文件,运行不再依赖 Libevent、Tokyocabinet 动态链接库。
7、HTTPSQS 旧版本如何升级到 HTTPSQS 1.6 版本:
HTTPSQS 1.6 版本完全兼容以前版本:编译安装 HTTPSQS 1.6,替换旧的 HTTPSQS,然后“kill httpsqs的进程ID”,按原来的启动参数启动 HTTPSQS 即可,数据完全兼容。
二、客户端:
1、客户端代码不再集成在 HTTPSQS 源码包中,可通过链接自行查看。
HTTPSQS 1.6 版本的详细使用说明,请访问: http://blog.s135.com/httpsqs/
HTTPSQS(HTTP Simple Queue Service)是一款基于 HTTP GET/POST 协议的轻量级开源简单消息队列服务,使用 Tokyo Cabinet 的 B+Tree Key/Value 数据库来做数据的持久化存储。
项目网址:http://code.google.com/p/httpsqs/
使用文档:http://blog.s135.com/httpsqs/
使用环境:Linux(同时支持32位、64位操作系统,推荐使用64位操作系统)
软件作者:张宴
队列(Queue)又称先进先出表(First In First Out),即先进入队列的元素,先从队列中取出。加入元素的一头叫“队头”,取出元素的一头叫“队尾”。利用消息队列可以很好地异步处理数据传送和存储,当你频繁地向数据库中插入数据、频繁地向搜索引擎提交数据,就可采取消息队列来异步插入。另外,还可以将较慢的处理逻辑、有并发数量限制的处理逻辑,通过消息队列放在后台处理,例如FLV视频转换、发送手机短信、发送电子邮件等。
HTTPSQS 具有以下特征:
● 非常简单,基于 HTTP GET/POST 协议。PHP、Java、Perl、Shell、Python、Ruby等支持HTTP协议的编程语言均可调用。
● 非常快速,入队列、出队列速度超过10000次/秒。
● 高并发,支持上万的并发连接,C10K不成问题。
● 支持多队列。
● 单个队列支持的最大队列数量高达10亿条。
● 低内存消耗,海量数据存储,存储几十GB的数据只需不到100MB的物理内存缓冲区。
● 可以在不停止服务的情况下便捷地修改单个队列的最大队列数量。
● 可以实时查看队列状态(入队列位置、出队列位置、未读队列数量、最大队列数量)。
● 可以查看指定队列ID(队列点)的内容,包括未出、已出的队列内容。
● 查看队列内容时,支持多字符集编码。
● 源代码不超过800行,适合二次开发。
HTTPSQS 1.6 版本更新内容:
一、服务器端:
1、修正了定时将内存缓冲区内容同步到磁盘,有时候出现段错误,导致进程崩溃的BUG。感谢以下网友的反馈:



2、修正了判断队列已满,遗漏的一种情况。感谢以下网友的反馈:


3、改为父子进程模式,生产环境稳定性更高。
4、改进了 ps 命令查看 httpsqs 的用户体验:

5、增加了密码校验功能(通过以下启动参数设置密码,通过URL参数“/?auth=密码”访问):

6、改为静态编译,编译完成后的 HTTPSQS 二进制文件,运行不再依赖 Libevent、Tokyocabinet 动态链接库。
7、HTTPSQS 旧版本如何升级到 HTTPSQS 1.6 版本:
HTTPSQS 1.6 版本完全兼容以前版本:编译安装 HTTPSQS 1.6,替换旧的 HTTPSQS,然后“kill httpsqs的进程ID”,按原来的启动参数启动 HTTPSQS 即可,数据完全兼容。
二、客户端:
1、客户端代码不再集成在 HTTPSQS 源码包中,可通过链接自行查看。
HTTPSQS 1.6 版本的详细使用说明,请访问: http://blog.s135.com/httpsqs/
快速配置 Samba 将 Linux 目录映射为 Windows 驱动器,用于跨平台编程
[
2011-4-8 08:53 | by 张宴 ]
2011-4-8 08:53 | by 张宴 ]
[文章作者:张宴 本文版本:v1.0 最后修改:2011.04.08 转载请注明原文链接:http://blog.s135.com/samba_linux_windows/]
一、局域网内的 Linux 服务器上操作步骤:
1、安装samba(CentOS Linux):
2、创建www账号
3、创建samba配置文件
输入以下内容:
4、为samba用户www、root设立一个密码:
5、启动samba:
二、局域网内的 Windows 服务器上操作步骤:
一、局域网内的 Linux 服务器上操作步骤:
1、安装samba(CentOS Linux):
yum install samba system-config-samba samba-client samba-common
2、创建www账号
/usr/sbin/groupadd www
/usr/sbin/useradd -g www www
mkdir -p /data0/knose/
chmod 777 /data0/knose/
mkdir -p /data0/htdocs/
chown -R www:www /data0/htdocs/
chmod 777 /data0/htdocs/
cat /etc/passwd | mksmbpasswd.sh> /etc/samba/smbpasswd
/usr/sbin/useradd -g www www
mkdir -p /data0/knose/
chmod 777 /data0/knose/
mkdir -p /data0/htdocs/
chown -R www:www /data0/htdocs/
chmod 777 /data0/htdocs/
cat /etc/passwd | mksmbpasswd.sh> /etc/samba/smbpasswd
3、创建samba配置文件
mv -f /etc/samba/smb.conf /etc/samba/smb.conf.bak
vi /etc/samba/smb.conf
vi /etc/samba/smb.conf
输入以下内容:
引用
[global]
server string = Samba Server
security = user
encrypt passwords = yes
smb passwd file = /etc/samba/smbpasswd
[knose]
workgroup = root
netbios name = root
path = /data0/knose
browseable = yes
writeable = yes
[web]
workgroup = www
netbios name = www
path = /data0/htdocs
browseable = yes
writeable = yes
server string = Samba Server
security = user
encrypt passwords = yes
smb passwd file = /etc/samba/smbpasswd
[knose]
workgroup = root
netbios name = root
path = /data0/knose
browseable = yes
writeable = yes
[web]
workgroup = www
netbios name = www
path = /data0/htdocs
browseable = yes
writeable = yes
4、为samba用户www、root设立一个密码:
smbpasswd -a www
smbpasswd -a root
smbpasswd -a root
5、启动samba:
/sbin/service smb start
二、局域网内的 Windows 服务器上操作步骤:
Windows 上静态编译 Libevent 2.0.10 并实现一个简单 HTTP 服务器
[
2011-3-30 08:40 | by 张宴 ]
2011-3-30 08:40 | by 张宴 ]
[文章作者:张宴 本文版本:v1.0 最后修改:2011.03.30 转载请注明原文链接:http://blog.s135.com/libevent_windows/]
本文介绍了如何在 Windows 操作系统中,利用微软 Visual Studio 2005 编译生成 Libevent 2.0.10 静态链接库,并利用 Libevent 静态链接库,实现一个简单的 HTTP Web服务器程序:httpd.exe。
假设 Visual Studio 2005 的安装路径为“D:\Program Files\Microsoft Visual Studio 8\”,Libevent 2.0.10 解压后的路径为“D:\libevent-2.0.10-stable”。
一、编译生成 Libevent 2.0.10 静态链接库。
1、修改“D:\libevent-2.0.10-stable\event_iocp.c”、“D:\libevent-2.0.10-stable\evthread_win32.c”、“D:\libevent-2.0.10-stable\listener.c”三个文件,在文件开头分别加上一行:
2、鼠标点击Windows左下角的【开始】-【所有程序】,找到【Microsoft Visual Studio 2005】,执行下图中的脚本:

3、按照下图中的方法编译Libevent 2.0.10:

4、生成的“libevent.lib”、“libevent_core.lib”、“libevent_extras.lib”三个文件就是我们需要的 Libevent 静态链接库。

二、利用 Libevent 静态链接库,实现一个简单的 HTTP Web服务器程序
1、打开 Visual Studio 2005,新建一个项目

本文介绍了如何在 Windows 操作系统中,利用微软 Visual Studio 2005 编译生成 Libevent 2.0.10 静态链接库,并利用 Libevent 静态链接库,实现一个简单的 HTTP Web服务器程序:httpd.exe。
假设 Visual Studio 2005 的安装路径为“D:\Program Files\Microsoft Visual Studio 8\”,Libevent 2.0.10 解压后的路径为“D:\libevent-2.0.10-stable”。
一、编译生成 Libevent 2.0.10 静态链接库。
1、修改“D:\libevent-2.0.10-stable\event_iocp.c”、“D:\libevent-2.0.10-stable\evthread_win32.c”、“D:\libevent-2.0.10-stable\listener.c”三个文件,在文件开头分别加上一行:
#define _WIN32_WINNT 0x0500
2、鼠标点击Windows左下角的【开始】-【所有程序】,找到【Microsoft Visual Studio 2005】,执行下图中的脚本:

3、按照下图中的方法编译Libevent 2.0.10:

4、生成的“libevent.lib”、“libevent_core.lib”、“libevent_extras.lib”三个文件就是我们需要的 Libevent 静态链接库。

二、利用 Libevent 静态链接库,实现一个简单的 HTTP Web服务器程序
1、打开 Visual Studio 2005,新建一个项目

Windows 和 Linux 下生成以当前时间命名的文件
[
2011-2-28 15:33 | by 张宴 ]
2011-2-28 15:33 | by 张宴 ]
在 Windows、Linux 操作系统,分别利用BAT批处理文件和Shell脚本,生成类似“20110228_082905.txt”以“年月日_时分秒”命名的文件。
Windows BAT批处理文件:
Linux Shell 脚本:
Windows BAT批处理文件:
@echo off
set time_hh=%time:~0,2%
if /i %time_hh% LSS 10 (set time_hh=0%time:~1,1%)
set filename=%date:~,4%%date:~5,2%%date:~8,2%_%time_hh%%time:~3,2%%time:~6,2%
echo test >> %filename%.txt
set time_hh=%time:~0,2%
if /i %time_hh% LSS 10 (set time_hh=0%time:~1,1%)
set filename=%date:~,4%%date:~5,2%%date:~8,2%_%time_hh%%time:~3,2%%time:~6,2%
echo test >> %filename%.txt
Linux Shell 脚本:
#!/bin/sh
echo test >> $(date -d "today" +"%Y%m%d_%H%M%S").txt
echo test >> $(date -d "today" +"%Y%m%d_%H%M%S").txt

















![订阅回忆未来[张宴]的博客](http://pic1.s135.com/images/rewin/rss.gif)




