如何利用SSH Tunnel打洞

五 21st, 2012

通常我们将SSH当作更安全的TELNET在使用,实际上SSH还能帮助我们进行网络打洞,开辟隧道,解决很多实际工作中
的互联互通问题,这就是SSH tunnel,它属于端口映射技术(port forwarding),是建立在SSH连接上的一个加密
隧道,利用它可以放心传输数据而不用担心信息泄漏。正是由于它的加密传输,数据不容易在传输过程中被第三方窥探,
所以可以利用它来帮我们穿越”全世界最大的局域网”的限制,从而真正意义上的畅游Internet!

创建了SSH隧道之后,不用直接去访问远程服务器,相反你访问你本机的某个端口,SSH Client会把你的数据通过已建
立的加密通道转发到远程主机的目的端口去。这就是端口映射技术(port forwarding)名称的由来。

SSH隧道分三种

  • local forwarding: 主要用来提供常规的加密隧道,例如让IMAP协议通过这个加密隧道,避免密码在网络上被人监听到。
  • dynamic forwarding: 通常用来做socks代理,例如翻墙就是用的这种端口映射。
  • remote forwarding: 可以用于逆向穿透NAT。

  • Local Forwarding

  • 主要用来提供常规的加密隧道,主要是将本机某个端口,直接映射到远程机器的某端口上,来达到加密传输的目的。
    比如远程主机上有一个WEB服务,监听80端口,走的是不加密的HTTP协议,如果你想要确保登录时输入的帐号和密码
    的绝对安全,就可以使用SSH的Local Forwarding技术来实现加密传输。

    前提条件:你必须有远程主机的帐号和密码,并且能通过ssh登录上去。

    【windows配置】
    在PuTTY的Connection->SSH->Tunnels中创建一个Local的映射关系。比如,我们在Source Port中输入1443,
    在Destination中输入对方主机的IP地址:端口(例如192.168.214.129:80),然后选择Local,再点一下Add,
    在Forwarded ports中就会出现”L1443 192.168.214.129:80″,这时隧道就建好了,如果你现在通过SSH登录
    到这台主机,你与主机之间就会创建出一条SSH加密隧道,所有你发往本地1443端口的数据,都会通过SSH隧道传到
    对方主机的192.168.214.129:80这个socket上去。


    【linux配置】
    操作更简单,直接ssh -L 1443:192.168.214.129:80 192.168.214.129就可以了。

    之后在浏览器中输入http://localhost:1443就可以以安全方式访问192.168.214.129:80端口上的内容了。

  • Dynamic Forwarding

  • 假设我们所用的A机器无法直接访问C服务器,和D服务器,但B服务器能直接访问C和D,A与B又是通的,加上我们又有B
    机器的帐号和密码,能够以SSH登录。那么我们就可以借用B服务器来做Dynamic Forwarding。即我们通常所说的
    socks代理,这个使用场景最多,非常有用!

    【windows配置】
    只需在PuTTY的Connection->SSH->Tunnels中创建一个Dynamic的Foward端口。比如,我们可以在Source port
    中输入1080,然后选Dynamic,再点一下Add,在Forwarded ports中就会出现“D1080,这时隧道就设置好了,如果
    你现在再登陆到B这台主机上,你与B主机之间就会创建出一条SSH加密的通道,所有你发往本地1080端口的的数据,都
    会通过SSH隧道传到B主机上再发送出去,并把返回的结果也以相同的方式传回来。


    【linux配置】
    操作更简单,直接ssh 192.168.214.129 -D 1080就可以了。

    之后A机器就可以通过socks代理(代理地址localhost:1080),顺利访问C和D主机了。也可以通过SocksCapV2来
    达到透明使用socks的目的。

    标签:

    Wake on LAN之python实现

    五 20th, 2012
  • 什么是Wake on LAN?
  • WOL又称网络唤醒,它需要主板和网卡的支持,同时需要在主板BIOS的网卡设置中将“Wake On LAN”置成ON状态,这样在计算机关机的情况下(注意:电源不能断),主板仍会给网卡供电,这样我们就可以通过局域网的另一台机器给这台机器发送一个魔术包(Magic Packet)来远程激活它,使其唤醒。是不是很酷?开机都可以远程操作!

  • 什么是Magic Packet?
  • Magic Packet是一个广播帧(frame),通常用UDP进行发送,在Magic Packet内,先有连续6个”FF”(十六进制,换算成二进制即:11111111),即:FF FF FF FF FF FF,在连续6个”FF”之后,拼上16次对端MAC地址(十六进制,48Bit的MAC地址),一旦对端网卡侦测、解读、研判(广播)Magic Packet的内容,内容中的MAC地址与电脑自身的地址吻合,就会启动唤醒、开机的程序。

    # Magic Packet格式:
    0xFF * 6 + MAC地址 * 16
    
    # 解释:重复六次0xFF + 重复16次远程网卡的48位MAC地址
    # 魔术包长度总计: 6 * 8 + 48 * 16 = 812(Bit) = 102(Byte)
    


  • 发送Magic Packet的python实现
  • #!/usr/bin/env python
    # Wake on Lan 
    
    import socket
    import struct
    
    def wake_on_lan(mac):
    
        if len(mac) == 12:
            pass
        elif len(mac) == 12 + 5:
            sep = mac[2]
            mac = mac.replace(sep, '')
        else:
            raise ValueError('Incorrect MAC address format')
    
        strMagic = ''.join(['FF' * 6, mac * 16])
    
        data = ''
        for i in range(0, len(strMagic), 2):
            data = ''.join([data, struct.pack('B', int(strMagic[i : i + 2], 16))])
    
        sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        sock.bind(('192.168.214.129', 20000))
        sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
        sock.sendto(data, ('<broadcast>', 7)) 
    
    wake_on_lan('001F16155384')
    wake_on_lan('00:1F:16:15:53:84')
    wake_on_lan('00-1F-16-15-53-84')
    
    标签: ,

    subversion的一点实践记录

    五 19th, 2012
  • 安装subversion依赖包
  • yum install apr-util apr-util-devel
    yum install sqlite sqlite-devel
    yum install zlib zlib-devel
    yum install cyrus-sasl-md5
    
  • subversion源码包下载,编译与安装
  • wget http://apache.etoak.com/subversion/subversion-1.7.5.tar.bz2
    tar -jxvf subversion-1.7.5.tar.bz2
    cd subversion-1.7.5
    ./configure --prefix=/home/steven/subversion
    make; make install
    
  • 创建版本库
  • mkdir -p /share/svnreps/stevenlife
    svnadmin create /share/svnreps/stevenlife
    
  • 配置
  • vi /share/svnreps/stevenlife/conf/svnserve.conf
    
    [general]
    anon-access = none
    auth-access = write
    authz-db = authz
    realm = stevenlife
    
    [sasl]
    use-sasl = true
    min-encryption = 128
    max-encryption = 256
    
    vi /share/svnreps/stevenlife/conf/authz
    
    [aliases]
    [groups]
    staff = zhoulin
    
    [/]
    @staff = rw
    
  • 给svn配置sasl加密方式
  • vi /etc/sasl2/svn.conf
    
    pwcheck_method: auxprop
    auxprop_plugin: sasldb
    sasldb_path: /share/svnreps/stevenlife/conf/passwd
    mech_list: DIGEST-MD5
    
  • 创建密钥文件
  • cd /share/svnreps/stevenlife/conf
    rm passwd
    
    saslpasswd2 -c -f passwd -u stevenlife zhoulin
    Password:
    Again (for verification):
    
  • 查看密钥文件
  • sasldblistusers2 -f passwd
    zhoulin@stevenlife: userPassword
    
  • 启动svnserve
  • svnserve -d -r /share/svnreps/stevenlife/
    
  • 常用客户端命令
  • # 将stevenlife目录下的文件update到最新
    svn -r HEAD --username zhoulin --password zhoulin checkout svn://192.168.214.129/stevenlife ./stevenlife
    
    # 增量更新单个文件
    cd stevenlife
    svn up create_index.sh
    U    create_index.sh
    Updated to revision 3.
    
    # 增量更新当前目录下所有文件
    svn up *
    At revision 3.
    At revision 3.
    At revision 3.
    At revision 3.
    At revision 3.
    At revision 3.
    At revision 3.
    At revision 3.
    At revision 3.
    At revision 3.
    At revision 3.
    
    # 查看更新日志
    svn log create_index.sh
    ------------------------------------------------------------------------
    r3 | zhoulin | 2012-05-20 08:01:18 +0800 (Sun, 20 May 2012) | 1 line
    ------------------------------------------------------------------------
    r1 | zhoulin | 2012-05-20 07:35:52 +0800 (Sun, 20 May 2012) | 1 line
    ------------------------------------------------------------------------
    
    # 提交更新
    svn commit -m "update comment" create_index.sh
    Sending        create_index.sh
    Transmitting file data .
    Committed revision 4.
    
    # 新增文件
    svn add newfile
    A         newfile
    svn commit -m "" newfile
    Adding         newfile
    Transmitting file data .
    Committed revision 5.
    
    # 比较历史
    svn diff -r6:5 newfile
    Index: newfile
    ===================================================================
    --- newfile     (revision 6)
    +++ newfile     (revision 5)
    @@ -1 +0,0 @@
    -1111
    
    # 当前目录某文件与svn仓库现有版本比较
    svn diff newfile
    Index: newfile
    ===================================================================
    --- newfile     (revision 8 )
    +++ newfile     (working copy)
    @@ -1,2 +1,2 @@
    -----
    +0000
     2222
    
    # 当前目录某文件与svn仓库某历史版本比较
    svn diff -r 7 newfile
    Index: newfile
    ===================================================================
    --- newfile     (revision 7)
    +++ newfile     (working copy)
    @@ -1,2 +1,2 @@
    -1111
    +0000
     2222
    
    标签:

    与jar包有关的小脚本

    五 16th, 2012
  • 对比两jar包有何差异,脚本名:diff.py
  • #!/usr/bin/env python
    
    import sys
    import hashlib
    from zipfile import ZipFile
    
    if len(sys.argv) != 3: sys.exit(1)
    
    zip1 = ZipFile(sys.argv[1], 'r')
    zip2 = ZipFile(sys.argv[2], 'r')
    
    hash1 = {}
    hash2 = {}
    
    for filename in zip1.namelist():
    	content = zip1.read(filename)
    	hash1[filename] = hashlib.md5(content).hexdigest()
    
    for filename in zip2.namelist():
    	content = zip2.read(filename)
    	hash2[filename] = hashlib.md5(content).hexdigest()
    
    keys1 = hash1.keys()
    keys2 = hash2.keys()
    
    for k in keys1:
    	if k in keys2:
    		if hash1[k] != hash2[k]:
    			print 'UPT', k
    	else:
    		print 'ADD', k
    
    for k in keys2:
    	if k not in keys1:
    		print 'DEL', k
    

  • 运行示例:
  • steven@debian:~$ ./diff.py a/pce.jar b/pce.jar
    UPT com/ai/pce/common/FeatureSpecEnum.class
    ADD com/ai/pce/bean/AllNetConfBean.class
    UPT com/ai/pce/bean/OfferBean.class
    UPT com/ai/pce/bean/QueryTdBean.class
    UPT com/ai/pce/bean/QueryTdBean.java
    UPT com/ai/pce/bean/OfferBeanBySpecId.java
    UPT com/ai/pce/ivalues/IOfferValue.class
    UPT com/ai/pce/ivalues/IOfferValue.java
    ADD com/ai/pce/load/DefaultLoader.class
    UPT com/ai/pce/ivalues/IQueryTdValue.class
    UPT com/ai/pce/ivalues/IQueryTdValue.java
    UPT com/ai/pce/bean/OfferBean.java
    UPT com/ai/pce/bean/OfferBeanBySpecId.class
    UPT com/ai/pce/common/FeatureSpecEnum.java
    DEL com/ai/pce/common/SoBusiPriceSVImpl.java
    DEL sblogo.png
    


  • 在指定目录下递归找.class文件,脚本名:findclass.py
  • #!/usr/bin/env python
    
    import os
    import sys
    import hashlib
    from zipfile import ZipFile
    
    if len(sys.argv) != 3: sys.exit(1)
    
    dir = sys.argv[1]
    clazz = sys.argv[2].replace('.', '/')
    
    for root, dirs, files in os.walk(dir):
    	for e in files:
    		if not e.endswith('.jar'): continue
    
    		filepath = os.path.join(root, e)
    		zip = ZipFile(filepath, 'r')
    		for filename in zip.namelist():
    			if not filename.endswith('.class'): continue
    			if filename.split('.class')[0] == clazz:
    				print filepath, filename
    


  • 运行示例:
  • steven@debian:~$ ./findclass.py a com.ai.pce.common.EffEnum
    a/pce.jar com/ai/pce/common/EffEnum.class
    steven@debian:~$
    
    标签:

    EJB 3.x 无状态会话Bean

    五 13th, 2012

    编写一个简单的EJB,并通过远程客户端程序进行调研。

    环境:
    1. J2EE容器环境采用BES8.1
    2. CentOS6.2 X86_64

  • 远程接口CapitalRemote.java
  • package com.stevenlife.ejb3;
    
    import javax.ejb.Remote;
    
    @Remote
    public interface CapitalRemote {
    
    	String getCapitalName(String paramString);
    }
    


  • 本地接口CapitalLocal.java
  • package com.stevenlife.ejb3;
    
    import javax.ejb.Local;
    
    @Local
    public interface CapitalLocal {
    	String getCapitalName(String paramString);
    }
    


  • Session Bean的实现CapitalBean.java
  • package com.stevenlife.ejb3;
    
    import javax.ejb.Stateless;
    
    @Stateless(mappedName = "CapitalBean")
    public class CapitalBean implements CapitalRemote, CapitalLocal {
    
    	public String getCapitalName(String countryName) {
    		String capital = "No such country";
    
    		if (countryName.equalsIgnoreCase("India")) {
    			capital = "New Delhi";
    		}
    
    		if (countryName.equalsIgnoreCase("United States Of America")) {
    			capital = "Washington DC";
    		}
    
    		if (countryName.equalsIgnoreCase("China")) {
    			capital = "Bejing";
    		}
    
    		return capital;
    	}
    }
    


  • 配置ejb-jar.xml
  • <?xml version="1.0" encoding="UTF-8"?>
    <ejb-jar version="3.0" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLScheme-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/ejb-jar_3_0.xsd">
    
    	<description>
    		Example of a hello world stateless session bean
    	</description>
    
    	<enterprise-beans>
    	</enterprise-beans>
    
    	<assembly-descriptor>
    	</assembly-descriptor>
    </ejb-jar>
    


  • 配置bes-ejb-jar.xml
  • <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE bes-ejb-jar PUBLIC "-//BES Tech Service(HK) Co., Ltd.//DTD BES Application Server EJB 3.0.1//EN" "http://www.bessystem.com/appserver/dtds/bes-ejb-jar_3_0-1.dtd">
    
    <bes-ejb-jar>
    	<enterprise-beans>
    	</enterprise-beans>
    </bes-ejb-jar>
    


  • 客户端测试
  • public class Client {
    
    	public static void main(String[] args) {
    		try {
    			Properties p = new Properties();
    			p.put("java.naming.factory.initial", "com.bes.jndi.CtxFactory");
    			p.put("java.naming.provider.url", "sparkTCP://192.168.214.129:13000");
    			p.put("com.bes.jndi.cache.enabled", "true");
    			p.put("com.bes.jndi.sparkTCP.endpoints", "192.168.214.129:13000");
    			Context ctx = new InitialContext(p);
    
    			CapitalRemote countryCaptial = (CapitalRemote) ctx.lookup("CapitalBean");
    			String capital = countryCaptial.getCapitalName("United States Of America");
    			System.out.println(capital);
    
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    }
    


  • 输出
  • Washington DC
    
    标签:

    EJB 2.x 无状态会话Bean

    五 13th, 2012

    编写一个简单的字符串格式化EJB,他主要包含两个接口:转大写、转小写,并通过远程客户端程序进行调研。

    环境:
    1. J2EE容器环境采用BES8.1
    2. CentOS6.2 X86_64

  • 远程接口StringFormat.java
  • package com.stevenlife.ejb2;
    
    import java.rmi.RemoteException;
    import javax.ejb.EJBObject;
    
    /**
     * Remote interface of this EJB sample
     *
     * @author steven
     */
    public interface StringFormat extends EJBObject {
    
    	public String toUpperCase(String str) throws RemoteException;
    	public String toLowerCase(String str) throws RemoteException;
    }
    


  • 本地接口StringFormatHome.java
  • package com.stevenlife.ejb2;
    
    import java.rmi.RemoteException;
    
    import javax.ejb.CreateException;
    import javax.ejb.EJBHome;
    
    /**
     * Home interface of this EJB sample
     *
     * @author steven
     */
    public interface StringFormatHome extends EJBHome {
    
    	StringFormat create() throws RemoteException, CreateException;
    }
    


  • Session Bean的实现StringFormatBean.java
  • package com.stevenlife.ejb2;
    
    import javax.ejb.SessionBean;
    import javax.ejb.SessionContext;
    
    /**
     * Bean implementation of this EJB sample
     *
     * @author steven
     */
    public class StringFormatBean implements SessionBean {
    
    	private static final long serialVersionUID = -4863710949318144610L;
    
    	public String toUpperCase(String str) {
    		return str.toUpperCase();
    	}
    
    	public String toLowerCase(String str) {
    		return str.toLowerCase();
    	}
    
    	public void ejbCreate() {
    	}
    
    	public void ejbRemove() {
    	}
    
    	public void ejbActivate() {
    	}
    
    	public void ejbPassivate() {
    	}
    
    	public void setSessionContext(SessionContext ctx) {
    	}
    }
    


  • 部署描述文件ejb-jar.xml
  • <?xml version="1.0" encoding="UTF-8"?>
    
    <ejb-jar xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/ejb-jar_2_1.xsd" version="2.1">
    
    	<description><![CDATA[Hello EJB]]></description>
    	<display-name>Hello EJB</display-name>
    
    	<enterprise-beans>
    		<session>
    			<description><![CDATA[]]></description>
    			<ejb-name>StringFormat</ejb-name>
    			<home>com.stevenlife.ejb2.StringFormatHome</home>
    			<remote>com.stevenlife.ejb2.StringFormat</remote>
    			<ejb-class>com.stevenlife.ejb2.StringFormatBean</ejb-class>
    			<session-type>Stateless</session-type>
    			<transaction-type>Bean</transaction-type>
    		</session>
    	</enterprise-beans>
    
    	<assembly-descriptor>
    	</assembly-descriptor>
    </ejb-jar>
    


  • BES专有部署文件bes-ejb-jar.xml
  • <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE bes-ejb-jar PUBLIC "-//BES Tech Service(HK) Co., Ltd.//DTD BES Application Server EJB 2.1.1//EN" "http://www.bessystem.com/appserver/dtds/bes-ejb-jar_2_1-1.dtd">
    
    <bes-ejb-jar>
    	<enterprise-beans>
    		<ejb>
    			<ejb-name>StringFormat</ejb-name>
    			<jndi-name>StringFormatHome</jndi-name>
    		</ejb>
    	</enterprise-beans>
    </bes-ejb-jar>
    


  • 部署目录结构
  • HelloEJB
    |-- META-INF
    |   |-- MANIFEST.MF
    |   |-- bes-ejb-jar.xml
    |   `-- ejb-jar.xml
    `-- com
        `-- stevenlife
            `-- ejb2
                |-- StringFormat.class
                |-- StringFormatBean.class
                `-- StringFormatHome.class
    


  • 打包
  • [aiweb@centos HelloEJB]$ jar -cvf HelloEJB2X.jar *
    added manifest
    ignoring entry META-INF/
    adding: META-INF/ejb-jar.xml(in = 818) (out= 363)(deflated 55%)
    adding: META-INF/bes-ejb-jar.xml(in = 410) (out= 270)(deflated 34%)
    ignoring entry META-INF/MANIFEST.MF
    adding: com/(in = 0) (out= 0)(stored 0%)
    adding: com/stevenlife/(in = 0) (out= 0)(stored 0%)
    adding: com/stevenlife/ejb2/(in = 0) (out= 0)(stored 0%)
    adding: com/stevenlife/ejb2/StringFormatBean.class(in = 1144) (out= 520)(deflated 54%)
    adding: com/stevenlife/ejb2/StringFormatHome.class(in = 300) (out= 208)(deflated 30%)
    adding: com/stevenlife/ejb2/StringFormat.class(in = 300) (out= 209)(deflated 30%)
    


  • 直接在BES控制台选择HelloEJB2X.jar,作为EJB应用发布

  • 客户端测试,将bes-*.jar, javaee.jar都引进来
  • package test;
    
    import java.util.Properties;
    
    import javax.naming.Context;
    import javax.naming.InitialContext;
    import javax.rmi.PortableRemoteObject;
    import com.stevenlife.ejb2.StringFormat;
    import com.stevenlife.ejb2.StringFormatHome;
    
    public class Client {
    
    	public static void main(String[] args) {
    		try {
    			Properties p = new Properties();
    			p.put("java.naming.factory.initial", "com.bes.jndi.CtxFactory");
    			p.put("java.naming.provider.url", "sparkTCP://192.168.214.129:13000");
    			p.put("com.bes.jndi.cache.enabled", "true");
    			p.put("com.bes.jndi.sparkTCP.endpoints", "192.168.214.129:13000");
    
    			Context ctx = new InitialContext(p);
    			Object ref = ctx.lookup("StringFormatHome");
    			StringFormatHome home = (StringFormatHome) PortableRemoteObject.narrow(ref, StringFormatHome.class);
    			StringFormat obj = home.create();
    
    			System.out.println("call toUpperCase: " + obj.toUpperCase("Hello EJB2.X"));
    			System.out.println("call toLowerCase: " + obj.toLowerCase("Hello EJB2.X"));
    
    		} catch (java.rmi.RemoteException re) {
    			re.printStackTrace();
    		} catch (javax.ejb.CreateException ce) {
    			ce.printStackTrace();
    		} catch (Throwable t) {
    			t.printStackTrace();
    		}
    	}
    }
    


  • 输出
  • call toUpperCase: HELLO EJB2.X
    call toLowerCase: hello ejb2.x
    
    标签:

    Tokyo Cabinet入门

    五 8th, 2012

    Tokyo Cabinet (简称TC)是Mikio Hirabayashi开发的一种DBM的开发库,其数据文件只有一个,里面存放多个的数据记录,所有操作都是依据key做主键操作。key,value都可以是连续不定长,即可以是二进制,也可是是字符串。数据文件中的记录组织有三种模式,hash表,B+树,定长 数组。这三种数据库即可以只保存在内存中,也可以指定保持到硬盘。应用最广泛的,当然就是hash表了。

  • 作为hash表
  • 主键key必须是唯一的,方法有:按key来存储value到一个记录,按key来删除一个记录,按key来获取一个记录的value。另外还有一个获取所有key的方法,获取的key是不排序的。TC可以做为NDBM,GBM的替代品,因为有更高的性能。

  • 作为B+树
  • 当采用B+树时,可以存储相同key的多条记录,有存储,删除,读取的方法,还可以按照一定顺序来读取记录。

  • 作为定长数组
  • 做为一个定长数组,key必须是自然数,其它的和hash表完全一样,因为key是自然数,所以速度比hash表要快。

    单单的TC数据库用处不大,宿主程序需要进行很多开发。TC的作者开发了Tokyo Tyrant (TT)这个网络服务程序,除了自己的二进制协议,还提供了现在被广泛应用的HTTP协议,memcached协议来访问TC数据库,这样一来,一下子就扩展了TC的使用范围,让TC从一个单纯的开发库变成了易用,高效的数据库系统。

    TT支持的协议包括memcached的持续连接,http1.1的长连接,并且数据文件,有热备,更新日志,复制功能,这些都给TT很高的可用性和高性能。并且,TT内嵌lua脚本的支持,可以对数据进行处理。

  • 安装 Tokyo Cabinet
  • tar zxvf tokyocabinet-1.4.10.tar.gz
    cd tokyocabinet-1.4.10
    ./configure --prefix=/app/aicau/tc
    make
    make install
    cd ..
    


  • 安装 Tokyo Tyrant
  • tar tokyotyrant-1.1.17.tar.gz
    cd tokyotyrant-1.1.17
    ./configure --prefix=/app/aicau/tt --with-tc=/app/aicau/tc
    make
    make install
    


  • ttserver启动参数解析
  • $ /app/aicau/tt/bin/ttserver -h
    /app/aicau/tt/bin/ttserver: the server of Tokyo Tyrant
    
    usage:
      /app/aicau/tt/bin/ttserver [-host name] [-port num] [-thnum num] [-tout num] [-dmn] [-pid path] [-kl] [-log path] [-ld|-le] [-ulog path] [-ulim num] [-uas] [-sid num] [-mhost name] [-mport num] [-rts path] [-ext path] [-extpc name period] [-mask expr] [-unmask expr] [dbname]
    
    -host name : 指定需要绑定的服务器域名或IP地址。默认绑定这台服务器上的所有IP地址。
    -port num : 指定需要绑定的端口号。默认端口号为1978
    -thnum num : 指定线程数。默认为8个线程。
    -tout num : 指定每个会话的超时时间(单位为秒)。默认永不超时。
    -dmn : 以守护进程方式运行。
    -pid path : 输出进程ID到指定文件(这里指定文件名)。
    -log path : 输出日志信息到指定文件(这里指定文件名)。
    -ld : 在日志文件中还记录DEBUG调试信息。
    -le : 在日志文件中仅记录错误信息。
    -ulog path : 指定同步日志文件存放路径(这里指定目录名)。
    -ulim num : 指定每个同步日志文件的大小(例如128m)。
    -uas : 使用异步IO记录更新日志(使用此项会减少磁盘IO消耗,但是数据会先放在内存中,不会立即写入磁盘,如果重启服务器或ttserver进程被kill掉,将导致部分数据丢失。一般情况下不建议使用)。
    -sid num : 指定服务器ID号(当使用主辅模式时,每台ttserver需要不同的ID号)
    -mhost name : 指定主辅同步模式下,主服务器的域名或IP地址。
    -mport num : 指定主辅同步模式下,主服务器的端口号。
    -rts path : 指定用来存放同步时间戳的文件名。
    -ext path : 扩展的脚本文件
    -mask expr : 需要禁止的命令,多个命名用","隔开
    -unmaks expr : 允许的命令 
    


  • 启动 ttserver
  • aicau@steven:~$ vi start_ttserver.sh
    #!/bin/sh
    
    export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/app/aicau/tc/lib
    
    /app/aicau/tt/bin/ttserver -host 127.0.0.1 -port 11211 -thnum 8 -dmn \
    -pid /app/aicau/logs/ttserver.pid \
    -log /app/aicau/logs/ttserver.log \
    -le \
    -ulog /app/aicau/logs/ \
    -ulim 128m \
    -sid 1 \
    -rts /app/aicau/logs/ttserver.rts \
    /app/aicau/db/database.tch
    


    ./start_ttserver.sh
    


  • 试用
  • # 直接通过HTTP协议访问
    curl -X PUT http://127.0.0.1:11211/my_key -d "this is value"
    curl http://127.0.0.1:11211/my_key
    curl -X DELETE http://127.0.0.1:11211/my_key
    
    # 通过tshmgr命令行访问
    

    EJB集群技术

    五 5th, 2012

    Client端要访问EJB容器中EJB都是先要先访问JNDI命名服务器。所以J2EE的EJB服务器的实现集群(Cluster)核心也就围绕着JNDI。根据集群对于JNDI命名树在系统中管理和组织的不同,一般EJB集群可以分为下面三种:

  • JNDI树代理(Proxy)
  • Cluster中每个J2EE Application Server都维护一个自己的本地私有JNDI树,Cluster中的每个服务器不知道其它服务器的状态和存在情况,只有Proxy服务知道Cluster中每个服务器的状态,并且可以访问Cluster中任何一个服务器上的JNDI树,这就要求每个服务器在启动和启动后要不断地和Proxy服务保持联系,以便Proxy知道它们的工作情况和Cluster所有的EJB对象。Client访问EJB对象,首先要访问JNDI Proxy,通过Proxy,可以重新定向访问到Cluster中所有的EJB对象。这种方法的优点是实现简单,只需要设计一个JNDI Proxy代理。对于每个应用服务器不做复杂要求;而且系统的伸缩性好,要升级系统,只是简单增加服务器就可以。但这种方法有一个致命的缺点,就是Proxy服务要是失败,整个Cluster系统将无法正常工作,可靠性差。

  • 集中式JNDI树(主域名服务器)
  • 采用集中式集群时,整个集群系统中仅有一个主命名服务器,它负责管理和维护集群中一个全局、集中的JNDI树,集群中所有的EJB服务器在启动后,都要把要发布的对象绑定在这台命名服务器上,每个EJB服务器不需要维护自己的私有JNDI树,由这台主命名服务器来维护。假如在集群中一个EJB要在多个服务器上部署,那么每个服务器可以把同一个home对象绑定到命名服务器上,当一个客户从命名服务器请求访问这个EJB的home对象,可以将所有的home对象引用都返回给客户端,或者可以按一种均衡算法返回一个服务器的home对象引用。这种集中式方法要提高整个系统可靠性,必须考虑命名服务器的备份问题,往往在大系统同时采用多台命名服务器,命名服务器间可以采用JNDI树复制方式,或者采用EJB服务器在多台服务器上绑定方式。例如Sybase公司的EJB应用服务器就是采用这种方式,它采用采用CORBA Cos Naming Service集中的管理Cluster中所有应用服务器的JNDI树。采用这种集中式的设计模型,系统设计简单,但同时为系统带来了集中式所固有的缺陷。首先,当系统设计中要考虑到命名服务器备份问题,而且随着集群系统越来越大,命名服务器在整个系统种瓶颈问题越显突出。

  • 分布式JNDI树
  • 在这种模型中,Cluster中每台应用服务器都有自己的命名服务器,命名服务器不仅维护私有的本地JNDI树,同时维护一个全局共享JNDI树。本地JNDI树只绑定本地应用服务器中部署的对象,而全局JNDI树保存了Cluster中其他应用服务器上的本地JNDI树副本。这样Client访问任何一台命名服务器,通过它的本地私有和全局共享JNDI树就能定位整个系统中部署EJB对象。一般都是采用多播形式,当Cluster中一个应用服务器启动后,加入这个Cluster的多播组,然后再采用IP 多播技术复制它的本地JNDI树到Cluster中其他服务器上全局共享JNDI树,这样Cluster中其他服务器就拥有它的JNDI树副本。同时,这台应用服务器和Cluster中其它服务器之间一直要保持HeartBeats(心跳)检测,以随时检测其它服务器的活动状态,假如有一台服务器死机异常后,这台应用服务器就要从它的全局共享JNDI树中删除这台异常服务器JNDI副本,其它活动的服务器都要做类似的操作。这种分布式模型系统最大的优点是具有很强的伸缩性,系统中再添加一台服务器,其它的服务器可以不作任何的变动。而且整个系统采用分布式体系可用性增强,系统中任何一台服务器死机,都不会影响到整个系统的正常工作。这种方法也是目前采用最多的一种设计方法。BEA公司WebLogic应用服务器和JBoss应用服务器就采用这种设计方法。

    标签:

    Linode上安装LNMP环境笔记

    四 16th, 2012
  • 环境说明
  • 操作系统: CentOS6.2 i386
    VPS提供商: Linode
    操作用户:root
    实现目的:搭建LNMP环境


  • 使用root帐号安装基础软件
  • yum install cmake gcc gcc-c++ autoconf libjpeg libjpeg-devel libpng libpng-devel freetype freetype-devel libxml2 libxml2-devel zlib zlib-devel glibc glibc-devel glib2 glib2-devel bzip2 bzip2-devel ncurses ncurses-devel curl curl-devel e2fsprogs e2fsprogs-devel krb5 krb5-devel libidn libidn-devel openssl openssl-devel openldap openldap-devel nss_ldap openldap-clients openldap-servers patch perl-ExtUtils-MakeMaker pcre pcre-devel gd-devel libjpeg-devel libpng-devel freetype-devel libxml2-devel curl-devel freetype-devel bison gcc gcc-c++ autoconf automake zlib* libxml* ncurses-devel libtool-ltdl-devel*


  • 下载软件
  • [root@kkkvps tools]# cd ~/tools
    [root@kkkvps tools]# ls -lh
    total 42M
    -rw-r--r-- 1 root root 4.8M Aug  8  2011 libiconv-1.14.tar.gz
    -rw-r--r-- 1 root root 1.3M Apr 16 15:49 libmcrypt-2.5.8.tar.gz
    -rw-r--r-- 1 root root 461K Apr 16 16:03 mcrypt-2.6.8.tar.gz
    -rw-r--r-- 1 root root 910K Apr 16 15:49 mhash-0.9.9.9.tar.gz
    -rw-r--r-- 1 root root  24M Oct 22 19:15 mysql-5.5.17.tar.gz
    -rw-r--r-- 1 root root 670K Nov  1 22:56 nginx-1.0.9.tar.gz
    -rw-r--r-- 1 root root  11M Jan 24 06:30 php-5.3.8.tar.bz2
    


  • 安装Mysql
  • # 添加mysql用户
    /usr/sbin/groupadd mysql
    /usr/sbin/useradd -g mysql mysql
    mkdir -p /data/mysql
    chown -R mysql:mysql /data/mysql

    # 安装Mysql
    tar -zxvf mysql-5.5.17.tar.gz
    cd mysql-5.5.17
    cmake . -DCMAKE_INSTALL_PREFIX=/usr/local/mysql -DMYSQL_DATADIR=/data/mysql -DSYSCONFDIR=/etc/
    make && make install

    # 设置Mysql
    #在support-files目录中有五个配置信息文件:
    #my-small.cnf (内存<=64M)
    #my-medium.cnf (内存 128M)
    #my-large.cnf (内存 512M)
    #my-huge.cnf (内存 1G-2G)
    #my-innodb-heavy-4G.cnf (内存 4GB)
    cd /usr/local/mysql
    cp ./support-files/my-medium.cnf /etc/my.cnf
    vi /etc/my.cnf
    #在 [mysqld] 段增加
    datadir = /data/mysql
    wait-timeout = 30
    max_connections = 512
    default-storage-engine = MyISAM
    #在 [mysqld] 段修改
    max_allowed_packet = 16M

    # 生成授权表
    cd /usr/local/mysql
    ./scripts/mysql_install_db --user=mysql

    # 更改密码
    /usr/local/mysql/bin/mysqladmin -u root password 123456

    # 开启mysql
    /usr/local/mysql/bin/mysqld_safe &

    # 测试连接mysql
    /usr/local/mysql/bin/mysql -u root -p 123456
    show databases;
    exit;

    # 设置开机启动
    vi /etc/rc.d/rc.local

    # 加入
    /usr/local/mysql/bin/mysqld_safe &


  • 编译安装PHP
  • #1
    tar -zxvf libiconv-1.14.tar.gz && cd libiconv-1.14/
    ./configure --prefix=/usr/local
    make && make install && cd ../
    
    #2
    tar -zxvf libmcrypt-2.5.8.tar.gz && cd libmcrypt-2.5.8/
    ./configure &&  make && make install
    /sbin/ldconfig && cd libltdl/ && ./configure --enable-ltdl-install
    make && make install && cd ../
    
    #3
    tar -zxvf mhash-0.9.9.9.tar.gz && cd mhash-0.9.9.9/ && ./configure
    make && make install && cd ../
    
    #4
    export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib:/usr/local/mysql/lib
    
    #5
    tar -zxvf mcrypt-2.6.8.tar.gz &&cd mcrypt-2.6.8/
    /sbin/ldconfig
    ./configure
    make && make install && cd ../
    
    #6
    tar -xjvf php-5.3.8.tar.bz2
    cd php-5.3.8
    
    ./configure --prefix=/usr/local/php \
    --with-config-file-path=/usr/local/php/etc \
    --with-iconv-dir=/usr/local/ --with-freetype-dir \
    --with-mysql=/usr/local/mysql \
    --with-mysqli=/usr/local/mysql/bin/mysql_config \
    --with-jpeg-dir --with-png-dir --with-zlib \
    --with-mhash --enable-sockets --enable-ftp \
    --with-libxml-dir --enable-xml --disable-rpath \
    --enable-safe-mode --enable-bcmath \
    --enable-shmop --enable-sysvsem \
    --enable-inline-optimization --with-curl \
    --with-curlwrappers \
    --enable-mbregex \
    --enable-mbstring --with-mcrypt --with-gd \
    --enable-gd-native-ttf --with-openssl --with-mhash \
    --enable-pcntl --enable-sockets --with-ldap --with-ldap-sasl \
    --enable-fpm \
    --with-xmlrpc --enable-zip --enable-soap \
    --without-pear \
    
    make ZEND_EXTRA_LIBS='-liconv'
    
    # 有可能发生错误
    # cp: cannot stat `ext/phar/phar.phar': No such file or directory
    
    # 解决方法 cd  ext/phar/
    # cp ./phar.php  ./phar.phar
    # cd ../..
    # 重新 make ZEND_EXTRA_LIBS='-liconv'
    
    make install
    cp php.ini-production /usr/local/php/etc/php.ini
    


  • 更改PHP-FPM
  • cp /usr/local/php/etc/php-fpm.conf.default /usr/local/php/etc/php-fpm.conf
    vi /usr/local/php/etc/php-fpm.conf

    # 修改成如下配置;
    pm.max_children = 64
    pm.start_servers = 5
    pm.min_spare_servers = 2
    pm.max_spare_servers = 5
    pm.max_requests = 1024
    user = webapp
    group = webapp

    # 检查语法是否正确
    /usr/local/php/sbin/php-fpm -t

    # 出现NOTICE: configuration file /usr/local/php/etc/php-fpm.conf test is successful 测试成功
    /usr/local/php/sbin/php-fpm &

    # 设置开机启动
    vi /etc/rc.d/rc.local

    # 在行末加入
    /usr/local/php/sbin/php-fpm &


  • 安装Nginx
  • #安装Nginx
    tar -zxvf nginx-1.0.9.tar.gz && cd nginx-1.0.9 &&
    ./configure --user=www --group=www \
    --prefix=/usr/local/nginx \
    --sbin-path=/usr/local/nginx/sbin/nginx \
    --conf-path=/usr/local/nginx/conf/nginx.conf \
    --with-http_stub_status_module \
    --with-http_ssl_module \
    --with-pcre \
    --lock-path=/var/run/nginx.lock \
    --pid-path=/var/run/nginx.pid
    
    make && make install && cd ../
    
    #更改配置
    vi /usr/local/nginx/conf/nginx.conf
    
    # 修改一些参数,别直接替换文件,这只是一部分
    user webapp
    
    events {
        use epoll;
        worker_connections  1024;
    }
    
    location ~ \.php$ {
                root           html;
                fastcgi_pass   127.0.0.1:9000;
                fastcgi_index  index.php;
                fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
                include        fastcgi_params;
            }
    
    #检测配置文件
    /usr/local/nginx/sbin/nginx -t
    
    # 提示表示成功
    # nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
    # nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
    
    # 开启Nginx
    /usr/local/nginx/sbin/nginx
    
    # 平滑重启Nginx
    /usr/local/nginx/sbin/nginx -s reload
    
    # 添加开机启动
    vi /etc/rc.d/rc.local
    
    # 最后移行加入
    /usr/local/nginx/sbin/nginx
    
    #测试
    cd /usr/local/nginx/html/
    touch index.php
    vi /usr/local/nginx/html/index.php
    
    <?php
       phpinfo();
    ?>
    
    标签:

    多进程并发一键式起停tuxedo服务

    二 25th, 2012

    写了个一键式起停tuxedo服务的小程序,这下省心多了-_^

    #!/usr/bin/python
    
    import os
    import sys
    import time
    import random
    import telnetlib
    from processing import Process, Queue
    from optparse import OptionParser
    
    cmdmap = {'start' : 'tmboot -y', 'stop' : 'tmshutdown -y'}
    
    ctxs = [
    	{'ID' : '1', 'IP' : '10.173.a,200', 'USER' : 'tuxapp', "PSWD" : 'tuxapp'},
    	{'ID' : '2', 'IP' : '10.173.a.201', 'USER' : 'tuxapp', "PSWD" : 'tuxapp'},
    	{'ID' : '3', 'IP' : '10.173.a.202', 'USER' : 'tuxapp', "PSWD" : 'tuxapp'},
    	{'ID' : '4', 'IP' : '10.173.a.203', 'USER' : 'tuxapp', "PSWD" : 'tuxapp'},
    	{'ID' : '5', 'IP' : '10.173.a.200', 'USER' : 'tuxbil', "PSWD" : 'tuxbil'},
    	{'ID' : '6', 'IP' : '10.173.a.201', 'USER' : 'tuxbil', "PSWD" : 'tuxbil'},
    	{'ID' : '7', 'IP' : '10.173.a.202', 'USER' : 'tuxbil', "PSWD" : 'tuxbil'},
    	{'ID' : '8', 'IP' : '10.173.a.203', 'USER' : 'tuxbil', "PSWD" : 'tuxbil'},
    	{'ID' : '9', 'IP' : '10.173.a.200', 'USER' : 'tuxbat', "PSWD" : 'tuxbat'},
    	{'ID' :'10', 'IP' : '10.173.a.201', 'USER' : 'tuxbat', "PSWD" : 'tuxbat'},
    	{'ID' :'11', 'IP' : '10.173.a.202', 'USER' : 'tuxbat', "PSWD" : 'tuxbat'},
    	{'ID' :'12', 'IP' : '10.173.a.203', 'USER' : 'tuxbat', "PSWD" : 'tuxbat'},
    	{'ID' :'13', 'IP' : '10.173.a.200', 'USER' : 'tuxitf', "PSWD" : 'tuxitf'},
    	{'ID' :'14', 'IP' : '10.173.a.201', 'USER' : 'tuxitf', "PSWD" : 'tuxitf'},
    	{'ID' :'15', 'IP' : '10.173.a.202', 'USER' : 'tuxitf', "PSWD" : 'tuxitf'},
    	{'ID' :'16', 'IP' : '10.173.a.203', 'USER' : 'tuxitf', "PSWD" : 'tuxitf'},
    ]
    
    def trace(func):
    	def wrapper(*args, **kv):
    		start = time.time()
    		print 'start job: %2s, IP =%15s, USER = %s' % (ctx['ID'], ctx['IP'], ctx['USER'])
    		func(*args, **kv)
    		print 'finished job: %2s elapsed time: %3ds' % (ctx['ID'], time.time() - start)
    	return wrapper
    
    @trace
    def do_action(queue, cmd):
    	ctx = queue.get()
    
    #	time.sleep(random.randint(1, 5))
    	addr = ctx.get('IP')
    	user = ctx.get('USER')
    	pswd = ctx.get('PSWD')
    
    	tn = telnetlib.Telnet(addr)
    	tn.read_until('login:')
    	tn.write(user + '\n')
    
    	tn.read_until('assword:')
    	tn.write(pswd + '\n')
    
    	tn.read_until(']$')
    	tn.write(cmd + '\n')
    
    	tn.read_until(']$')
    	tn.write("exit\n")
    	print tn.read_all()
    	tn.close()
    
    p = OptionParser(usage="%prog -a $action", version="%prog 1.0")
    p.add_option('-a', dest = 'action', help = 'start | stop')
    (opts, args) = p.parse_args()
    if not opts.action in ('start', 'stop'):
    	p.print_help()
    	sys.exit(-1)
    
    queue = Queue()
    p = None
    for ctx in ctxs:
    	queue.put(ctx)
    	p = Process(target = do_action, args=(queue, cmdmap.get(opts.action)))
    	p.start()
    
    p.join()
    
    标签: ,