<?xml version="1.0" encoding="UTF-8"?><rss version="2.0">
	<channel>
		<title>ATHER Shu(A.S)的Blog</title>
		<link>http://www.asarea.cn</link>
		<description>ATHER Shu的blog，新的开始！</description> 
		<language>zh-CN</language>
		<copyright>Copyright 2013-2014, ASAREA.CN</copyright>
		<webMaster>shushenghong@gmail.com</webMaster>
		<pubDate>Sat, 30 Nov 2024 11:18:18 +0800</pubDate>
		<lastBuildDate>Sat, 30 Nov 2024 13:18:43 +0800</lastBuildDate>
	<item><title><![CDATA[js的锁以及异步调用相关]]></title><description><![CDATA[js通过引入async await promise来解决异步回调地狱问题。<br/>思考下面的两个场景<br/>注：以下示例代码均用typescript实现<br/><br/><pre><div class='code language-js'>let i = 0;<br/>async function handler() {<br/>&nbsp;&nbsp;&nbsp;&nbsp;i++;<br/>&nbsp;&nbsp;&nbsp;&nbsp;console.log(new Date().getTime()/1000, '处理程序开始', i);<br/>&nbsp;&nbsp;&nbsp;&nbsp;await new Promise(resolve =&gt; setTimeout(resolve, 2000)); // 模拟异步操作<br/>&nbsp;&nbsp;&nbsp;&nbsp;console.log(new Date().getTime()/1000, '处理程序完成', i);<br/>};<br/></div></pre><br/>场景一：直接调用handler两次<br/><pre><div class='code language-js'>function call1() {<br/>&nbsp;&nbsp;&nbsp;&nbsp;handler();<br/>&nbsp;&nbsp;&nbsp;&nbsp;handler();<br/>}<br/>call1();<br/></div></pre><br/>打印如下：<br/><pre><div class='code'>1732934781.962 处理程序开始 1<br/>1732934781.966 处理程序开始 2<br/>1732934783.969 处理程序完成 2<br/>1732934783.97 处理程序完成 2<br/></div></pre>可以看出，两次handler都同时先后进入（由于js单线程，i会变化），并同时卡在await等待2s。<br/><br/>场景二：await调用handler两次<br/><pre><div class='code language-js'>async function call2() {<br/>&nbsp;&nbsp;&nbsp;&nbsp;await handler();<br/>&nbsp;&nbsp;&nbsp;&nbsp;await handler();<br/>}<br/>call2();<br/></div></pre><br/>打印如下：<br/><pre><div class='code'>1732934929.563 处理程序开始 1<br/>1732934931.569 处理程序完成 1<br/>1732934931.57 处理程序开始 2<br/>1732934933.571 处理程序完成 2<br/></div></pre><br/>可以看出，下一次的handler会等上一次执行完毕再进行。<br/><br/>由此可以看出，js如果直接调用函数2次，函数中开头非异步的部分会按调用顺序执行，并同时卡在函数中异步的部分，异步结束后再执行剩余部分。<br/><br/>这很可能造成数据不同步等各种问题。对于要求不管是直接调用还是await调用多次，都要完全保证顺序的地方，需要引入锁机制。<br/><br/>核心就是，函数在进入时立即锁住，即便是直接调用多次，也会确定等待锁释放。<br/>而根据前面的试验结论，可以用一个简单的异步promise来实现这个锁。<br/><pre><div class='code language-js'>let lastlock = Promise.resolve();<br/>async function getlock() {<br/>&nbsp;&nbsp;&nbsp;&nbsp;let unlock = () =&gt; {};<br/>&nbsp;&nbsp;&nbsp;&nbsp;let lock = lastlock;<br/>&nbsp;&nbsp;&nbsp;&nbsp;let nlock = new Promise&lt;void&gt;((resolve) =&gt; {unlock = resolve;});<br/>&nbsp;&nbsp;&nbsp;&nbsp;lastlock = nlock;<br/>&nbsp;&nbsp;&nbsp;&nbsp;await lock;<br/>&nbsp;&nbsp;&nbsp;&nbsp;return unlock;<br/>}<br/></div></pre><br/>上面的getlock函数，核心要点<br/>1. lastlock一开始是一个已经resolve的promise，所以await它不会阻塞<br/>2. 每次获取锁，js单线程执行会更改lastlock为一个新的promise，而这个promise的resolve函数会被传出来，也就成了一个unlock函数，这个unlock执行会resolve promise，完成异步。<br/><br/>改造handler函数，用锁<br/><pre><div class='code language-js'>async function handler() {<br/>&nbsp;&nbsp;&nbsp;&nbsp;const unlock = await getlock();<br/>&nbsp;&nbsp;&nbsp;&nbsp;try&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i++;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;console.log(new Date().getTime()/1000, '处理程序开始', i);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;await new Promise(resolve =&gt; setTimeout(resolve, 2000)); // 模拟异步操作<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;console.log(new Date().getTime()/1000, '处理程序完成', i);<br/>&nbsp;&nbsp;&nbsp;&nbsp;} finally {<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unlock();<br/>&nbsp;&nbsp;&nbsp;&nbsp;}<br/>};<br/></div></pre><br/>连续直接调用handler两次(即call1())<br/><pre><div class='code language-js'>1732935948.492 处理程序开始 1<br/>1732935950.497 处理程序完成 1<br/>1732935950.497 处理程序开始 2<br/>1732935952.499 处理程序完成 2<br/></div></pre><br/>连续await调用handler两次(即call2())，打印如下<br/><pre><div class='code language-js'>1732936175.165 处理程序开始 1<br/>1732936177.171 处理程序完成 1<br/>1732936177.171 处理程序开始 2<br/>1732936179.173 处理程序完成 2<br/></div></pre>]]></description><link>http://www.asarea.cn/diary/319</link><guid>http://www.asarea.cn/diary/319</guid><comments>http://www.asarea.cn/diary/319#comments</comments><author>shushenghong@gmail.com(A.S)</author><pubDate>Sat, 30 Nov 2024 11:18:18 +0800</pubDate></item><item><title><![CDATA[golang学习之函数/方法/接口]]></title><description><![CDATA[函数：golang按值传参，会自动拷贝（对于方法声明如果是以struct自身定义，struct宿主自身也会自动拷贝），如果形参是零值为nil的引用类型，其实也是传递拷贝，只不过因为拷贝出的形参变量指向的跟实参指向的是同一个地址，可能通过引用间接修改实参变量指向的值<br/><br/>一个interface（接口）类型，由Type和Value组成，当Type和Value都是nil时，接口值才为空<br/>1.如果形参是接口类型，传递任意具体类型变量，会将type设置为变量的具体类型，value设置为变量具体的值（变量需实现了此接口）<br/>2.接口调用方法时，会动态解出Value值进行对应的方法调用<br/>3.指向接口类型的指针没有任何意义<br/><pre><div class='code'>Type 类型<br/>Value 值<br/></div></pre>]]></description><link>http://www.asarea.cn/diary/318</link><guid>http://www.asarea.cn/diary/318</guid><comments>http://www.asarea.cn/diary/318#comments</comments><author>shushenghong@gmail.com(A.S)</author><pubDate>Thu, 06 Jan 2022 17:52:24 +0800</pubDate></item><item><title><![CDATA[golang学习之零值]]></title><description><![CDATA[golang里面的零值<br/><pre><div class='code language-golang'>类型 零值<br/>string ""<br/>int 0<br/>float 0<br/>bool false<br/>数组(固定长度) 所有成员的零值<br/>struct 所有成员的零值<br/>slice nil<br/>map nil<br/>指针 nil<br/>函数 nil<br/>通道 nil<br/>接口interface Type Value均为nil<br/></div></pre><br/><pre><div class='code language-golang'>package main<br/><br/>import "fmt"<br/><br/>func main() {<br/>&nbsp;&nbsp;&nbsp;&nbsp;type Man struct {<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name int<br/>&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;type Human interface {<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GetName() string<br/>&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;var (<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a string<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b int<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c float32<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;d bool<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e [3]int<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f Man<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g []int<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;h map[string]string<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i *int<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;j func() int<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;k chan int<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;l Human<br/>&nbsp;&nbsp;&nbsp;&nbsp;)<br/>&nbsp;&nbsp;&nbsp;&nbsp;fmt.Printf("a=%#v b=%#v c=%#v d=%#v e=%#v f=%#v g=%#v h=%#v i=%#v j=%#v k=%#v l=%#v\n", a, b, c, d, e, f, g, h, i, j, k, l)<br/><br/>}<br/><br/>// a="" b=0 c=0 d=false e=[3]int{0, 0, 0} f=main.Man{name:0} g=[]int(nil) h=map[string]string(nil) i=(*int)(nil) j=(func() int)(nil) k=(chan int)(nil) l=&lt;nil&gt;<br/><br/></div></pre>]]></description><link>http://www.asarea.cn/diary/317</link><guid>http://www.asarea.cn/diary/317</guid><comments>http://www.asarea.cn/diary/317#comments</comments><author>shushenghong@gmail.com(A.S)</author><pubDate>Thu, 06 Jan 2022 16:40:10 +0800</pubDate></item><item><title><![CDATA[hello, 2018]]></title><description><![CDATA[Let's start.]]></description><link>http://www.asarea.cn/diary/316</link><guid>http://www.asarea.cn/diary/316</guid><comments>http://www.asarea.cn/diary/316#comments</comments><author>shushenghong@gmail.com(A.S)</author><pubDate>Thu, 06 Jan 2022 16:39:02 +0800</pubDate></item><item><title><![CDATA[字体类型名词解释]]></title><description><![CDATA[serif: 衬线字体，如宋体<br/>sans-serif: 无衬线字体，如黑体，雅黑<br/>monospace：等宽字体<br/><br/><img src='/res/upload/QQ20150118-1_20150118112851.png' alt='QQ20150118-1' title='QQ20150118-1'/><br/><img src='/res/upload/QQ20150118-2_20150118113014.png' alt='QQ20150118-2' title='QQ20150118-2'/><br/><br/>参考：<br/><a href='http://zh.wikipedia.org/wiki/%E6%97%A0%E8%A1%AC%E7%BA%BF%E4%BD%93' target=_blank>无衬线字体</a><br/><a href='http://zh.wikipedia.org/wiki/%E7%AD%89%E5%AE%BD%E5%AD%97%E4%BD%93' target=_blank>等宽字体</a>]]></description><link>http://www.asarea.cn/diary/315</link><guid>http://www.asarea.cn/diary/315</guid><comments>http://www.asarea.cn/diary/315#comments</comments><author>shushenghong@gmail.com(A.S)</author><pubDate>Sun, 18 Jan 2015 11:30:22 +0800</pubDate></item><item><title><![CDATA[获取mysql表注释以及列注释]]></title><description><![CDATA[获取表注释：<br/><pre><div class='code'>use xx_database;<br/>show table status;<br/></div></pre>最后一列就是<br/><pre><div class='code'>+-----------------+--------+---------+------------+------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+-------------+------------+-----------------+----------+----------------+---------+<br/>| Name&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| Engine | Version | Row_format | Rows | Avg_row_length | Data_length | Max_data_length | Index_length | Data_free | Auto_increment | Create_time&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | Update_time | Check_time | Collation&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | Checksum | Create_options | Comment |<br/>+-----------------+--------+---------+------------+------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+-------------+------------+-----------------+----------+----------------+---------+<br/>| game&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | InnoDB |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;10 | Compact&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;0 |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0 |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 16384 |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0 |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0 |&nbsp;&nbsp; 7340032 |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1 | 2014-11-13 15:18:13 | NULL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| NULL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | utf8_general_ci |&nbsp;&nbsp;&nbsp;&nbsp; NULL |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |<br/>| goods&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| InnoDB |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;10 | Compact&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;0 |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0 |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 16384 |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0 |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0 |&nbsp;&nbsp; 7340032 |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1 | 2014-11-13 15:20:18 | NULL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| NULL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | utf8_general_ci |&nbsp;&nbsp;&nbsp;&nbsp; NULL |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |<br/></div></pre><br/>获取列注释：<br/><pre><div class='code'>show full fields from xxx_table;</div></pre>最后一列就是<br/><pre><div class='code'>+------------+------------------+-----------------+------+-----+---------+----------------+---------------------------------+---------+<br/>| Field&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| Type&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | Collation&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | Null | Key | Default | Extra&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| Privileges&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| Comment |<br/>+------------+------------------+-----------------+------+-----+---------+----------------+---------------------------------+---------+<br/>| id&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | int(10) unsigned | NULL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| NO&nbsp;&nbsp; | PRI | NULL&nbsp;&nbsp;&nbsp;&nbsp;| auto_increment | select,insert,update,references |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |<br/>| name&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | varchar(200)&nbsp;&nbsp;&nbsp;&nbsp; | utf8_general_ci | NO&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp; | NULL&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| select,insert,update,references |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |<br/>| url&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| varchar(1000)&nbsp;&nbsp;&nbsp;&nbsp;| utf8_general_ci | NO&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp; | NULL&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| select,insert,update,references |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |<br/>| created_at | int(10) unsigned | NULL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| NO&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp; | NULL&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| select,insert,update,references |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |<br/>| updated_at | int(10) unsigned | NULL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| NO&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp; | NULL&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| select,insert,update,references |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |<br/>+------------+------------------+-----------------+------+-----+---------+----------------+---------------------------------+---------+<br/></div></pre>]]></description><link>http://www.asarea.cn/diary/314</link><guid>http://www.asarea.cn/diary/314</guid><comments>http://www.asarea.cn/diary/314#comments</comments><author>shushenghong@gmail.com(A.S)</author><pubDate>Thu, 13 Nov 2014 15:56:32 +0800</pubDate></item><item><title><![CDATA[php连接ms sql数据库的一些问题]]></title><description><![CDATA[由于项目需要从mssql导入数据到mysql数据库，记录下php连接mssql的一些问题。<br/><br/>1、安装，需要安装freetds<br/>对于Debian（ubuntu这种）<br/><pre><div class='code'>apt-get install php5-sybase <br/></div></pre><br/>2、字符集问题<br/>mssql query如果返回<br/><pre><div class='code'>"Unicode data in a Unicode-only collation or ntext data cannot be sent to clients using DB-Library (such as ISQL) or ODBC version 3.7 or earlier."</div></pre><br/>编辑/etc/freetds/freetds.conf，添加如下两行:<br/><pre><div class='code'>[global]<br/>;tds version = 4.2<br/>tds version = 8.0<br/>client charset = UTF-8<br/></div></pre>也可以在php.ini或者mssql独立module的ini（譬如ubuntu上php各个子module都有自己的独立配置文件）中指定charset<br/><pre><div class='code'>; Specify client character set..<br/>; If empty or not set the client charset from freetds.comf is used<br/>; This is only used when compiled with FreeTDS<br/>mssql.charset = "UTF-8"<br/></div></pre><br/><br/>3、date format问题<br/>默认mssql返回的时间类型是：mon dd yyyy hh:miAM (or PM)<br/>这种格式插入不到mysql中（Incorrect date value），在php中也不支持，如new DateTime()。<br/><br/>解决方法一种是用mssql的convert语法，<br/>另一种是设置php.ini或者mssql module的独立ini，加入<br/><pre><div class='code'>mssql.datetimeconvert = Off<br/></div></pre><br/>参考：<br/><a href='http://php.net/manual/zh/function.mssql-query.php' target=_blank>mssql-query</a><br/><a href='http://msdn.microsoft.com/en-us/library/ms187928.aspx' target=_blank>mssql cast&convert</a>]]></description><link>http://www.asarea.cn/diary/313</link><guid>http://www.asarea.cn/diary/313</guid><comments>http://www.asarea.cn/diary/313#comments</comments><author>shushenghong@gmail.com(A.S)</author><pubDate>Mon, 15 Sep 2014 20:32:14 +0800</pubDate></item><item><title><![CDATA[virtualbox虚拟网络：NAT&bridge桥接网络]]></title><description><![CDATA[记录下virtualbox最常用的两种虚拟网络方式NAT和bridge桥接：<br/>1、NAT<br/>虚拟机virualmachine（下简称vm）对外界不可见，vm通过host主机访问外网。可以设置端口映射，将host主机的某些端口映射到VM的端口，这样外界访问host主机的端口会自动转发到VM的对应端口。<br/><img src='/res/upload/nat_20140825224250.png' alt='nat' title='nat'/><br/><br/>这也是最方便简洁的方式。<br/><br/>2、bridge桥接<br/>（这里演示下host是win7，vm是ubuntu的情况。）<br/>vm与host平起平坐，外界看起来就像是两台机器，vm有自己独立的ip。<br/>vm通过主机的某网卡虚拟出一块网卡桥接到internet。<br/>2.1 选择主机网卡，设置bridge<br/><img src='/res/upload/bridge_20140825224913.png' alt='bridge' title='bridge'/><br/>2.2 启动后会发现多了一块网卡<br/><img src='/res/upload/ifconfig1_20140825224830.png' alt='ifconfig1' title='ifconfig1'/><br/>2.2 修改interface文件（这个文件相当于windows里的设置网络属性如ip、网关、子网掩码等，dhcp就是自动获得ip）<br/><pre><div class='code'>vim /etc/network/interfaces</div></pre><img src='/res/upload/interface_20140825224834.png' alt='interface' title='interface'/><br/>2.3 启动网卡<br/><img src='/res/upload/ifup_20140825224832.png' alt='ifup' title='ifup'/><br/>2.4 查看ip<br/><img src='/res/upload/ifconfig2_20140825224831.png' alt='ifconfig2' title='ifconfig2'/><br/><br/>这种方式能模拟出一台真是机器来。<br/><br/>PS：NAT和bridge模式可以并存。]]></description><link>http://www.asarea.cn/diary/312</link><guid>http://www.asarea.cn/diary/312</guid><comments>http://www.asarea.cn/diary/312#comments</comments><author>shushenghong@gmail.com(A.S)</author><pubDate>Mon, 25 Aug 2014 22:58:09 +0800</pubDate></item><item><title><![CDATA[php图片加水印]]></title><description><![CDATA[花了点时间为博客图片上传加水印功能。<br/>其实很简单，用的无非是imagecopymerge或者imagecopy方法。<br/>imagecopymerge可以设置水印透明度（可以总体设置水印图片透明度，但是水印图片自身不能带有alpha）。<br/>imagecopy直接把水印覆盖到原图上（水印图片支持自身带有alpha，但不能总体设置水印图片透明度）。<br/><br/>如果想要水印图片带有alpha如png，同时又要支持设置整体水印图片透明度，则需要hack。<br/><pre><div class='code language-php'>/**<br/> * PNG ALPHA CHANNEL SUPPORT for imagecopymerge();<br/> * This is a function like imagecopymerge but it handle alpha channel well!!!<br/> **/<br/>function imagecopymerge_alpha($dst_im, $src_im, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h, $pct){<br/>&nbsp;&nbsp;&nbsp;&nbsp;$opacity=$pct;<br/>&nbsp;&nbsp;&nbsp;&nbsp;// getting the watermark width<br/>&nbsp;&nbsp;&nbsp;&nbsp;$w = imagesx($src_im);<br/>&nbsp;&nbsp;&nbsp;&nbsp;// getting the watermark height<br/>&nbsp;&nbsp;&nbsp;&nbsp;$h = imagesy($src_im);<br/>&nbsp;&nbsp;&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;// creating a cut resource<br/>&nbsp;&nbsp;&nbsp;&nbsp;$cut = imagecreatetruecolor($src_w, $src_h);<br/>&nbsp;&nbsp;&nbsp;&nbsp;// copying that section of the background to the cut<br/>&nbsp;&nbsp;&nbsp;&nbsp;imagecopy($cut, $dst_im, 0, 0, $dst_x, $dst_y, $src_w, $src_h);<br/>&nbsp;&nbsp;&nbsp;&nbsp;// inverting the opacity<br/>&nbsp;&nbsp;&nbsp;&nbsp;$opacity = $opacity;<br/>&nbsp;&nbsp;&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;// placing the watermark now<br/>&nbsp;&nbsp;&nbsp;&nbsp;imagecopy($cut, $src_im, 0, 0, $src_x, $src_y, $src_w, $src_h);<br/>&nbsp;&nbsp;&nbsp;&nbsp;imagecopymerge($dst_im, $cut, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h, $opacity);<br/></div></pre><br/>参考资料：<a href='http://sina.salek.ws/content/alpha-support-phps-imagecopymerge-function' target=_blank>Alpha support for PHP's imagecopymerge function</a><br/><br/>演示：<br/><img src='/res/upload/qinshi_20140815225719.png' alt='qinshi' title='qinshi'/>]]></description><link>http://www.asarea.cn/diary/311</link><guid>http://www.asarea.cn/diary/311</guid><comments>http://www.asarea.cn/diary/311#comments</comments><author>shushenghong@gmail.com(A.S)</author><pubDate>Fri, 15 Aug 2014 22:58:50 +0800</pubDate></item><item><title><![CDATA[windows查看端口占用情况]]></title><description><![CDATA[<pre><div class='code'>netstat -ano | findstr "8083"<br/>TCP&nbsp;&nbsp;&nbsp;&nbsp;0.0.0.0:8083&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0.0.0.0:0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LISTENING&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5288<br/><br/>tasklist | findstr "5288"<br/>VBoxHeadless.exe&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5288 Console&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1&nbsp;&nbsp;&nbsp;&nbsp; 20,432 K<br/></div></pre>]]></description><link>http://www.asarea.cn/diary/310</link><guid>http://www.asarea.cn/diary/310</guid><comments>http://www.asarea.cn/diary/310#comments</comments><author>shushenghong@gmail.com(A.S)</author><pubDate>Thu, 31 Jul 2014 21:19:30 +0800</pubDate></item><item><title><![CDATA[android安卓activity生命周期]]></title><description><![CDATA[写了个小例子测试安卓activity生命周期，总结如下：<br/><img src='/res/upload/andriod activity_20140712102959.png' alt='andriod activity' title='andriod activity'/><br/><br/>代码如下：<br/><pre><div class='code language-java'>package cn.asarea.app.testandroid;<br/><br/>import android.os.Bundle;<br/>import android.app.Activity;<br/>import android.util.Log;<br/>import android.view.Menu;<br/><br/>public class MainActivity extends Activity {<br/>&nbsp; &nbsp; private static final String TAG = "test andriod";<br/><br/>&nbsp; &nbsp; @Override<br/>&nbsp; &nbsp; protected void onCreate(Bundle savedInstanceState) {<br/>&nbsp; &nbsp; &nbsp; &nbsp; super.onCreate(savedInstanceState);<br/>&nbsp; &nbsp; &nbsp; &nbsp; setContentView(R.layout.activity_main);<br/>&nbsp; &nbsp; &nbsp; &nbsp; <br/>&nbsp; &nbsp; &nbsp; &nbsp; Log.e(TAG, Thread.currentThread().getStackTrace()[2].getMethodName());<br/>&nbsp; &nbsp; }<br/><br/>&nbsp; &nbsp; @Override<br/>&nbsp; &nbsp; protected void onStart() {<br/>&nbsp; &nbsp; &nbsp; &nbsp; // TODO Auto-generated method stub<br/>&nbsp; &nbsp; &nbsp; &nbsp; super.onStart();<br/>&nbsp; &nbsp; &nbsp; &nbsp; <br/>//&nbsp; &nbsp; &nbsp; &nbsp; StackTraceElement stackTraceElements[] =&nbsp;&nbsp;Thread.currentThread().getStackTrace();<br/>//&nbsp; &nbsp; &nbsp; &nbsp; for (StackTraceElement stackTraceElement : stackTraceElements) {<br/>//&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Log.e(TAG, stackTraceElement.getClassName() + ":" + stackTraceElement.getMethodName());<br/>//&nbsp; &nbsp; &nbsp; &nbsp; }<br/>&nbsp; &nbsp; &nbsp; &nbsp; <br/>&nbsp; &nbsp; &nbsp; &nbsp; Log.e(TAG, Thread.currentThread().getStackTrace()[2].getMethodName());<br/>&nbsp; &nbsp; }<br/><br/>&nbsp; &nbsp; @Override<br/>&nbsp; &nbsp; protected void onRestart() {<br/>&nbsp; &nbsp; &nbsp; &nbsp; // TODO Auto-generated method stub<br/>&nbsp; &nbsp; &nbsp; &nbsp; super.onRestart();<br/>&nbsp; &nbsp; &nbsp; &nbsp; <br/>&nbsp; &nbsp; &nbsp; &nbsp; Log.e(TAG, Thread.currentThread().getStackTrace()[2].getMethodName());<br/>&nbsp; &nbsp; }<br/><br/>&nbsp; &nbsp; @Override<br/>&nbsp; &nbsp; protected void onResume() {<br/>&nbsp; &nbsp; &nbsp; &nbsp; // TODO Auto-generated method stub<br/>&nbsp; &nbsp; &nbsp; &nbsp; super.onResume();<br/>&nbsp; &nbsp; &nbsp; &nbsp; <br/>&nbsp; &nbsp; &nbsp; &nbsp; Log.e(TAG, Thread.currentThread().getStackTrace()[2].getMethodName());<br/>&nbsp; &nbsp; }<br/><br/>&nbsp; &nbsp; @Override<br/>&nbsp; &nbsp; protected void onPause() {<br/>&nbsp; &nbsp; &nbsp; &nbsp; // TODO Auto-generated method stub<br/>&nbsp; &nbsp; &nbsp; &nbsp; super.onPause();<br/>&nbsp; &nbsp; &nbsp; &nbsp; <br/>&nbsp; &nbsp; &nbsp; &nbsp; Log.e(TAG, Thread.currentThread().getStackTrace()[2].getMethodName());<br/>&nbsp; &nbsp; }<br/><br/>&nbsp; &nbsp; @Override<br/>&nbsp; &nbsp; protected void onStop() {<br/>&nbsp; &nbsp; &nbsp; &nbsp; // TODO Auto-generated method stub<br/>&nbsp; &nbsp; &nbsp; &nbsp; super.onStop();<br/>&nbsp; &nbsp; &nbsp; &nbsp; <br/>&nbsp; &nbsp; &nbsp; &nbsp; Log.e(TAG, Thread.currentThread().getStackTrace()[2].getMethodName());<br/>&nbsp; &nbsp; }<br/><br/>&nbsp; &nbsp; @Override<br/>&nbsp; &nbsp; protected void onDestroy() {<br/>&nbsp; &nbsp; &nbsp; &nbsp; // TODO Auto-generated method stub<br/>&nbsp; &nbsp; &nbsp; &nbsp; super.onDestroy();<br/>&nbsp; &nbsp; &nbsp; &nbsp; <br/>&nbsp; &nbsp; &nbsp; &nbsp; Log.e(TAG, Thread.currentThread().getStackTrace()[2].getMethodName());<br/>&nbsp; &nbsp; }<br/><br/>&nbsp; &nbsp; @Override<br/>&nbsp; &nbsp; public boolean onCreateOptionsMenu(Menu menu) {<br/>&nbsp; &nbsp; &nbsp; &nbsp; // Inflate the menu; this adds items to the action bar if it is present.<br/>&nbsp; &nbsp; &nbsp; &nbsp; getMenuInflater().inflate(R.menu.main, menu);<br/>&nbsp; &nbsp; &nbsp; &nbsp; return true;<br/>&nbsp; &nbsp; }<br/><br/>}<br/></div></pre>]]></description><link>http://www.asarea.cn/diary/309</link><guid>http://www.asarea.cn/diary/309</guid><comments>http://www.asarea.cn/diary/309#comments</comments><author>shushenghong@gmail.com(A.S)</author><pubDate>Sat, 12 Jul 2014 10:31:47 +0800</pubDate></item><item><title><![CDATA[/etc/shadow中特殊密码含义]]></title><description><![CDATA[NP means nopassword<br/>!! means user account has not been initialed or has not been locked.<br/>! means group password is not available.<br/>* means login disabled.<br/><br/>参考：<br/><a href='http://www.cyberciti.biz/faq/understanding-etcshadow-file/' target=_blank>Understanding /etc/shadow file</a><br/><a href='http://www.berlinix.com/linux/shadow.php' target=_blank>Shadow - 密码文件</a>]]></description><link>http://www.asarea.cn/diary/308</link><guid>http://www.asarea.cn/diary/308</guid><comments>http://www.asarea.cn/diary/308#comments</comments><author>shushenghong@gmail.com(A.S)</author><pubDate>Fri, 04 Jul 2014 13:43:57 +0800</pubDate></item><item><title><![CDATA[git初探]]></title><description><![CDATA[一直想把存在自己本机的svn库放到外网服务器上，这样可以多台电脑check代码，考虑到svn中心库需要经常备份，防止损坏，决定改用分布式的git，不用担心中心库挂掉，也就放心许多。<br/><br/>以下是自己根据查阅到的资料整理记录，<br/>1、git是分布式的，但是并不是说没有中心服务器的概念，只不过任何一台clone了代码的电脑都可以成为中心服务器。譬如A、B都从C服务器clone了一份git代码，C坏了，A、B都可以恢复成为中心服务器。<br/><br/>2、git的分层<br/>用惯了svn的人脑海里只有本地workspace和远程库两层概念，本地workspace开发完了就往远程库commit。简单粗暴。<br/>对于git，则要加入一层，本地库。本地workspace往本地库commit，本地库再push到远程库。（你可以这样想，本地库是远程库的完整拷贝，所以才可以分布式，才可以离线提交）<br/>我画的一张草图^_^（去年第一次用git时整的）<br/><img src='/res/upload/git_20140625175911.jpg' alt='git' title='git'/><br/>中心库目录<br/><img src='/res/upload/git2_20140625180203.png' alt='git2' title='git2'/><br/>本地库是中心库的完整拷贝（所谓clone，clone的就是.git目录）<br/><img src='/res/upload/git3_20140625180332.png' alt='git3' title='git3'/><br/><br/><br/>3、安装git，<br/>对于ubuntu，<br/><pre><div class='code'>apt-get install git</div></pre>mac，mac os预安装了git<br/>windows，安装<a href='http://msysgit.github.com/' target=_blank>msysgit</a><br/><br/>4、初始化一个中心库<br/>root登录到服务器，<br/><pre><div class='code'>#cd到你准备存放库的目录<br/>git init --bare myproject.git<br/>#这就会新建一个目录叫myproject.git，并且初始化了一个git库<br/>#bare的意思就是不需要workspace，只要.git中的git信息内容<br/></div></pre><br/>5、决定中心库git的访问方式<br/>就是别人怎么check中心库的代码，方式很多，有ssh、git、http等方式，<br/>可以参考<a href='http://git-scm.com/book/zh/%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%B8%8A%E7%9A%84-Git' target=_blank>服务器上的git</a><br/>这里简单说下ssh方式。说白了就是用ssh（用过putty吧，输入用户名密码就登陆到远程机器了）登陆某个特定账户，<br/>譬如新建一个账号git，ssh登陆该账号访问git中心库所在的目录。<br/>5.1 创建git用户<br/><pre><div class='code'>adduser git<br/>#将创建的中心库改为git用户所有<br/>chown -R git:git myproject.git<br/>#禁止用putty等用git账号登陆<br/>vim /etc/passwd<br/>#将git:x:1001:1001:,,,:/home/git:/bin/bash改为<br/>git:x:1001:1001:,,,:/home/git:/usr/bin/git-shell<br/></div></pre><br/>5.2 ssh登陆的两种方式，<br/>一种是用户名密码，总不能告诉所有要check代码的人git账户的密码吧，略搓。<br/>一种就是用授权key，让要check代码的人生成一个RSA密钥，将公钥传到中心服务器的authorized_keys中。<br/>具体这些网上有很多说明，请参考：<br/><a href='http://git-scm.com/book/zh/%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%B8%8A%E7%9A%84-Git-%E7%94%9F%E6%88%90-SSH-%E5%85%AC%E9%92%A5' target=_blank>服务器上的 Git - 生成 SSH 公钥</a><br/><br/>关于ssh登陆，请参考<a href='http://www.ruanyifeng.com/blog/2011/12/ssh_remote_login.html' target=_blank>ssh原理</a><br/><br/>到了这里，别人就可以通过如：<br/>ssh://git@xxx.net:222/mygitposition/myproject.git<br/>的路径clone到代码了<br/><br/>6、进阶管理git的访问<br/>人肉往authorized_keys加key的方式对于大一点的团队是个噩梦，这就要借助其他开源项目：<br/>Gitosis、<a href='https://github.com/sitaramc/gitolite' target=_blank>Gitolite</a>（推荐，因为前者已经很久不更新了），用他们来帮助你管理ssh公钥。<br/><br/>7、初始化本地库<br/>对于本地库，用惯svn的人都想用乌龟，好像git也有人搞了个乌龟，这里不介绍，介绍两种方式<br/>一种用eclipse的插件egit（图形化操作哦，不比乌龟差）。<br/>一种用命令行（略潮）。<br/><br/>7.1 clone远程库<br/>如果远程库已经有详细的工程内容，可以直接clone下来玩。<br/>对于egit，直接import projects from git，填入中心库的项目访问地址，如<br/><pre><div class='code'>ssh://git@xxx.net:222/mygitposition/myproject.git</div></pre>对于命令行<br/><pre><div class='code'>#cd到你的workspace目录<br/>git clone ssh://git@xxx.net:222/mygitposition/myproject.git<br/>#工程会clone到myproject目录中<br/></div></pre><br/>7.2 用本地库充实中心库<br/>说白了也就是初次提交拉，你可以在本地建一个git库，从svn项目转换代码，或者人工加入一些初始文件，提交到本地git库，再统一push到远程中心库。<br/><br/>7.2.1 对于svn项目转换为git项目<br/><pre><div class='code'>#author.txt是将svn的账号转化为git账号<br/>#内容如：ather = Ather Shu &lt;shushenghong@gmail.com&gt;<br/>git svn clone http://localhost/svn/repository/myproject --authors-file=author.txt --no-metadata<br/>cd myproject<br/>#将svn ignore转化为git ignore<br/>#可以导出到exclude<br/>git svn show-ignore &gt; .git/info/exclude<br/>#或者生成.gitignore文件<br/>git svn create-ignore<br/></div></pre>这样一个本地的git库就初始化好了，详细的svn转git的资料，请参考<a href='http://git-scm.com/book/zh/Git-%E4%B8%8E%E5%85%B6%E4%BB%96%E7%B3%BB%E7%BB%9F-%E8%BF%81%E7%A7%BB%E5%88%B0-Git' target=_blank>svn转git</a><br/>下面就是把本地库push到远程中心库了<br/><pre><div class='code'>git remote add origin ssh://git@xxx.net:222/mygitposition/myproject.git<br/>git push origin master --tags <br/></div></pre><br/>7.2.2 用egit提交<br/>在eclipse工程里新建文件或者做修改，然后commit（这只是commit到了本地库），再push即可。<br/>egit使用起来比较简单，这里不多介绍，详细可以参考<a href='http://wiki.eclipse.org/EGit/User_Guide' target=_blank>egit用户手册</a><br/><br/>参考资料汇总：<br/><a href='http://git-scm.com/book/zh/%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%B8%8A%E7%9A%84-Git' target=_blank>服务器上的git</a><br/><a href='http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000/00137583770360579bc4b458f044ce7afed3df579123eca000' target=_blank>搭建Git服务器</a><br/><a href='http://git-scm.com/book/zh/%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%B8%8A%E7%9A%84-Git-%E7%94%9F%E6%88%90-SSH-%E5%85%AC%E9%92%A5' target=_blank>服务器上的 Git - 生成 SSH 公钥</a><br/><a href='http://www.ruanyifeng.com/blog/2011/12/ssh_remote_login.html' target=_blank>ssh原理</a><br/><a href='https://github.com/sitaramc/gitolite' target=_blank>Gitolite</a><br/><a href='http://git-scm.com/book/zh/Git-%E4%B8%8E%E5%85%B6%E4%BB%96%E7%B3%BB%E7%BB%9F-%E8%BF%81%E7%A7%BB%E5%88%B0-Git' target=_blank>svn转git</a><br/><a href='http://wiki.eclipse.org/EGit/User_Guide' target=_blank>egit用户手册</a>]]></description><link>http://www.asarea.cn/diary/307</link><guid>http://www.asarea.cn/diary/307</guid><comments>http://www.asarea.cn/diary/307#comments</comments><author>shushenghong@gmail.com(A.S)</author><pubDate>Wed, 25 Jun 2014 18:47:00 +0800</pubDate></item><item><title><![CDATA[email电子邮件概略]]></title><description><![CDATA[概述下最近查阅email相关资料的心得：<br/><br/>1.email这个东东比http诞生的早的多，是老古董了。<br/>据说70年代初世界上的第一封电子邮件发出。1987年9月14日中国第一封电子邮件是由“德国互联网之父”维纳·措恩与王运丰在北京的计算机应用技术研究所发往德国卡尔斯鲁厄大学的，“Across the Great Wall we can reach every corner in the world.&nbsp; &nbsp; ”。<br/><br/>2.email中的几个概念<br/>mailbox：可以想象成世界中真实的一个邮箱，每一封邮件最终都会存放在这里<br/>MUA：mail user agent，你可以把它想象成本地邮件编辑器、阅读器，譬如outlook编辑器将你输入的各种信息打包成一个email，收到邮件后又可以通过MUA来阅读。<br/>MTA：mail transport agent，这哥们就是个邮差：作为发送方，将MUA打包的邮件传送给下一站；作为接收方，将收到的邮件接收下来并RELAY或者扔给LDA。这个传送过程用的是smtp协议。<br/>sendMail是最早的实现smtp传输的smtp服务器程序（有一个接收MTA和一个发送MTA）<br/>smtp：Simple Mail Transfer Protocol，网络中传输email的协议，一般发送方MTA和接收方MTA会有一个握手过程。<br/>RELAY：转发，当接收方MTA收到邮件后，发现目的邮箱不是本服务器的，会向目的邮箱服务器的MTA转发。<br/>LDA：local delivery agent，接收方MTA收到邮件后，发现目的邮箱就是本服务器的，会调用LDA发送到一个具体的本机mailbox。<br/>MX解析：DNS解析，将email的域名服务器解析到对应ip的具体服务器。<br/>当有人发邮件给“vincen@example.com”时，系统将对“example.com”进行DNS中的MX记录解析。如果MX记录存在，系统就根据MX记录的优先级，将邮件转发到与该MX相应的邮件服务器上。<br/><br/>随着科技的发展，电脑越来越多，大部分电脑都通过ISP上网，并不是所有的电脑都有自己独立的域名，固定的ip。<br/>于是出现了远程mailbox，譬如163邮箱，qq邮箱等，这些mail服务商会提供给你一个邮件地址，将你的邮件存放在他们的服务器上。<br/>但是，我们又想在自己的电脑上阅读邮件怎么办？<br/>于是，POP/IMAP出现了，可以从远程mail服务器上pull邮件到本机。<br/>pop3：Post Office Protoco，POP3是把邮件从远程电子邮箱中传输到本地计算机的协议。<br/>imap：Internet Message Access Protocol，比pop3更强大，是其替代者，本地邮件客户端做的操作（已读、移动、删除等）能同步到远程服务器。<br/><br/>配置过本地邮件客户端如outlook等的都会知道要配置pop3/imap，就是为了从远程邮件服务器拉email到本地来。<br/>这里又有个疑问，既然pop3/imap都是取邮件的协议，那不是outlook这种都只能看邮件了？但是现实情况是我们也能发邮件啊。<br/>这就是上面说道的RELAY功能了，本地邮件客户端outlook譬如使用163邮箱发送邮件时，也有一个MTA（只不过这个MTA只是发送，不能接收），跟163的MTA通讯，一般这个通讯会加入额外的用户名、密码验证（授权RELAY），再通过163的MTA RELAY邮件到真正的收件人邮件服务器MTA。<br/><br/>参考资料：<br/><a href='http://www.tldp.org/HOWTO/Mail-Administrator-HOWTO-3.html' target=_blank>How Electronic Mail Works</a><br/><a href='http://linux.vbird.org/linux_server/0380sendmail.php' target=_blank>簡易 Mail Server 架設 -- Sendmail 設定</a><br/><a href='http://zh.wikipedia.org/wiki/SMTP' target=_blank>简单邮件传输协议</a><br/><a href='http://zh.wikipedia.org/wiki/%E7%94%B5%E5%AD%90%E9%82%AE%E4%BB%B6' target=_blank>电子邮件</a><br/><a href='http://help.163.com/09/1223/14/5R7P6CJ600753VB8.html' target=_blank>什么是POP3、SMTP和IMAP?</a>]]></description><link>http://www.asarea.cn/diary/306</link><guid>http://www.asarea.cn/diary/306</guid><comments>http://www.asarea.cn/diary/306#comments</comments><author>shushenghong@gmail.com(A.S)</author><pubDate>Wed, 11 Jun 2014 04:27:35 +0800</pubDate></item><item><title><![CDATA[OAuth初探]]></title><description><![CDATA[以前在做lishiju社交账号登录时，已经初步研究过国内的sina、qq、baidu OAuth登录，不过那时也是对着文档一步步走下来，倒也没有觉得有什么可以记录的。<br/><br/>最近在项目中遇到facebook、twitter、fitbit的集成，又用到了OAuth，却有了很大的困惑，究其原因是twitter、fitbit用的是OAuth1，而facebook用的是2.0，相比较而言，2.0的使用会简单很多。这里简单的做一点自己理解的记录。<br/><br/>1、OAuth 1.0（1.0a）<br/><br/>1.1 用户访问网站某个url，这个url可能是用于读取第三方如facebook等的资源或者是绑定第三方账号。<br/>1.2 网站检测本地数据库该用户是否有授权绑定过第三方账号（有就直接1.6）。<br/>1.3 网站向第三方请求一个临时令牌（request token），请求时需要开发者申请的app id和app secret。第三方认证后，返回一个临时令牌。<br/>1.4 网站收到临时令牌跳转到第三方的授权页面（需要传递临时令牌以及回调url），用户会在这个页面输入用户名密码登录并决定是否授权。（authorize）<br/>1.5 授权成功后第三方会跳转到本地网站的回调url（会以get方式把临时令牌、授权信息oauth_verifier），此时网站就可以根据临时令牌以及返回的授权信息调用第三方接口转换为最终的访问令牌（access token）<br/>1.6 此后就可以访问api了，当然需要在http调用api的头部加入access token以及token secret等等很多很多参数（很恶心）<br/><img src='/res/upload/oauth1_20140428033116.png' alt='oauth1' title='oauth1'/><br/><br/>参考：<br/><a href='http://zh.wikipedia.org/wiki/OAuth' target=_blank>OAuth维基百科</a><br/><a href='https://dev.twitter.com/docs/auth/implementing-sign-twitter' target=_blank>twitter oauth流程</a><br/><a href='https://wiki.fitbit.com/display/API/OAuth+Authentication+in+the+Fitbit+API' target=_blank>fitbit流程</a><br/><br/>2、OAuth2<br/>OAuth2.0的最大改变就是不需要临时token了，直接authorize生成授权code，用code就可以换取access token了，同时access token加入过期，刷新机制，为了安全，要求第三方的授权接口必须是https的。<br/><br/>2.1 用户访问网站某个url，这个url可能是用于读取第三方如facebook等的资源或者是绑定第三方账号。<br/>2.2 网站检测本地数据库该用户是否有授权绑定过第三方账号（有就直接2.5）。<br/>2.3 网站向第三方申请授权（authorize），请求时需要开发者申请的app id以及回调url，用户会在这个页面输入用户名密码登录并决定是否授权。（authorize）<br/>2.4 授权成功后第三方会跳转到本地网站的回调url（会以get方式返回授权信息Authorization Code），网站根据code以及app id、appi secret换取最终的访问令牌（access token）<br/>2.5 此后就可以访问api了，只需在http调用的url里以get方式传递access_token参数即可<br/><img src='/res/upload/oauth2_20140428035906.png' alt='oauth2' title='oauth2'/><br/><br/>参考：<br/><a href='http://tools.ietf.org/html/rfc6749' target=_blank>The OAuth 2.0 Authorization Framework</a><br/><a href='https://developers.facebook.com/docs/facebook-login/access-tokens/' target=_blank>facebook OAuth</a><br/><a href='http://wiki.connect.qq.com/%E5%BC%80%E5%8F%91%E6%94%BB%E7%95%A5_server-side' target=_blank>QQ OAuth</a><br/><a href='http://developer.baidu.com/wiki/index.php?title=docs/oauth/authorization' target=_blank>baidu OAuth</a><br/><a href='http://open.weibo.com/wiki/%E6%8E%88%E6%9D%83%E6%9C%BA%E5%88%B6%E8%AF%B4%E6%98%8E' target=_blank>微博 OAuth</a><br/><br/>其他一些的作者的日志：<br/><a href='http://blog.sina.com.cn/s/blog_4c9ba28501015ux6.html' target=_blank>Oauth1.0与oauth2.0的区别</a><br/><a href='http://huoding.com/2011/11/08/126' target=_blank>OAuth的改变</a><br/><a href='http://blog.csdn.net/biangren/article/details/7683340' target=_blank>新浪微博OAuth2.0 VS OAuth1.0 主要区别</a>]]></description><link>http://www.asarea.cn/diary/304</link><guid>http://www.asarea.cn/diary/304</guid><comments>http://www.asarea.cn/diary/304#comments</comments><author>shushenghong@gmail.com(A.S)</author><pubDate>Mon, 28 Apr 2014 04:05:57 +0800</pubDate></item><item><title><![CDATA[解决vim小键盘不好使]]></title><description><![CDATA[打开putty设置，Terminal-&gt;Features，勾选Disable application keypad mode。<br/><img src='/res/upload/vim keypad_20140418075146.png' alt='vim keypad' title='vim keypad'/><br/><br/>putty设置永不断线<br/><img src='/res/upload/putty_20140428075939.png' alt='putty' title='putty'/><br/><br/>virtualbox不显示虚拟机窗口启动，按住shift再点启动按钮。<br/>As of VirtualBox 4.2, you can start a headless machine from the GUI by holding shift while you click the "Start" button.]]></description><link>http://www.asarea.cn/diary/303</link><guid>http://www.asarea.cn/diary/303</guid><comments>http://www.asarea.cn/diary/303#comments</comments><author>shushenghong@gmail.com(A.S)</author><pubDate>Mon, 28 Apr 2014 08:50:06 +0800</pubDate></item><item><title><![CDATA[eclipse里svn账号修改]]></title><description><![CDATA[eclipse里想要切换个svn账号，需要先删掉老的，找了半天。<br/><img src='/res/upload/eclipse svn_20140417161037.png' alt='eclipse svn' title='eclipse svn'/>]]></description><link>http://www.asarea.cn/diary/302</link><guid>http://www.asarea.cn/diary/302</guid><comments>http://www.asarea.cn/diary/302#comments</comments><author>shushenghong@gmail.com(A.S)</author><pubDate>Thu, 17 Apr 2014 16:12:24 +0800</pubDate></item><item><title><![CDATA[插卡无文件]]></title><description><![CDATA[本想给小p孩下几首歌听听，谁知便携音箱插入sd卡、u盘都显示插卡无文件，搞了半天原来是只支持fat32的格式，不支持ntfs，把sd卡重新格式化了下，选择fat32即可，备查。<br/><img src='/res/upload/插卡无文件_20140414104204.png' alt='插卡无文件' title='插卡无文件'/>]]></description><link>http://www.asarea.cn/diary/301</link><guid>http://www.asarea.cn/diary/301</guid><comments>http://www.asarea.cn/diary/301#comments</comments><author>shushenghong@gmail.com(A.S)</author><pubDate>Mon, 14 Apr 2014 10:42:13 +0800</pubDate></item><item><title><![CDATA[asarea.cn域名回归及博客重构、历史剧网重构]]></title><description><![CDATA[流水账记下最近的几件事：<br/>1、asarea.cn域名失散3年后，终于回归了，再次启用。<br/>2、又看了看原先写的博客代码，实在是不忍直视，又吧啦吧啦重构了一番。<br/>3、用bootstrap3重构了<a href='http://www.lishiju.net' target=_blank>历史剧网</a>一番，无论是手机、平板、电脑都可以自如展示了。<br/><img src='/res/upload/手机改版_20140323130407.png' alt='手机改版' title='手机改版'/><br/>4、实现了微信公众号：历史剧网的开发者接口，关注后现在可以输入关键词搜索相关历史信息了。<br/><img src='/res/upload/Screenshot_2014-02-25-20-42-00_20140323130919.png' alt='历史剧网微信' title='历史剧网微信'/><br/><img src='/res/upload/Screenshot_2014-02-24-20-02-48_20140323130917.png' alt='历史剧网微信' title='历史剧网微信'/><br/>欢迎关注历史剧网微信公众号，搜索添加lishijunet，或扫描二维码。<br/><img src='/res/upload/wx_20140323130816.jpg' alt='wx' title='wx'/>]]></description><link>http://www.asarea.cn/diary/300</link><guid>http://www.asarea.cn/diary/300</guid><comments>http://www.asarea.cn/diary/300#comments</comments><author>shushenghong@gmail.com(A.S)</author><pubDate>Sun, 23 Mar 2014 13:09:54 +0800</pubDate></item><item><title><![CDATA[nodejs初体验]]></title><description><![CDATA[这几天搭了个websocket，在选择服务器端选择了nodejs，也算是第一次正式体验nodejs吧。<br/><br/>成品在:<a href='http://www.lishiju.net/exam' target=_blank>http://www.lishiju.net/exam</a>，是个考试服务器，支持多人在线抢答等。<br/><br/>nodejs确实很方便，写过js的人用起来那叫一个爽。大概说说我的理解吧，nodejs本身是在google v8 js引擎基础上，用c写了(当然用了一些异步库)很多很基础的核心扩展模块，如events、fs、net、http等等，然后再封装成js供使用者使用。<br/>在这些核心扩展基础上，开发者可以自由发挥做出各种各种的新的扩展，这些扩展可以通过npm工具发布到一个相当于nodejs库市场的地方，可以很方便的用npm install **来安装各种各样的扩展。<br/><br/>nodejs很强大，不像php那样通常需要依赖apache来运行，nodejs是一个完整的生态系统，既是一个运行平台又可以说是一种语言环境，而且也是跨平台的。<br/>譬如express扩展就是在核心net http的基础上搭出来的web server（含server + 后台具体业务逻辑如展现网页等），独立于任何webserver就可以运行起来。<br/>另外nodejs还有一些譬如forever的扩展，能够将nodejs程序封装成系统服务运行。<br/><br/>关于nodejs的开发环境，sublime 开发 + eclipse调试（安装chrome developer tools）。<br/><br/>好吧，随便扯这么多吧。]]></description><link>http://www.asarea.cn/diary/299</link><guid>http://www.asarea.cn/diary/299</guid><comments>http://www.asarea.cn/diary/299#comments</comments><author>shushenghong@gmail.com(A.S)</author><pubDate>Thu, 13 Feb 2014 17:06:57 +0800</pubDate></item>	</channel>
</rss>
