2009年4月26日
**
* <pre>
* Title: HttpRequestProxy.java
* Project: HP-Common
* Type: com.hengpeng.common.web.HttpRequestProxy
* Author: benl
* Create: 2007-7-3 上午03:07:07
* Copyright: Copyright (c) 2007
* Company:
* <pre>
*/
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.log4j.Logger;
/**
* <pre>
* HTTP请求代理类
* </pre>
*
* @author benl
* @version 1.0, 2007-7-3
*/
public class HttpRequestProxy
{
/**
* 连接超时
*/
private static int connectTimeOut = 5000;
/**
* 读取数据超时
*/
private static int readTimeOut = 10000;
/**
* 请求编码
*/
private static String requestEncoding = "GBK";
private static Logger logger = Logger.getLogger(HttpRequestProxy.class);
/**
* <pre>
* 发送带参数的GET的HTTP请求
* </pre>
*
* @param reqUrl HTTP请求URL
* @param parameters 参数映射表
* @return HTTP响应的字符串
*/
public static String doGet(String reqUrl, Map parameters,
String recvEncoding)
{
HttpURLConnection url_con = null;
String responseContent = null;
try
{
StringBuffer params = new StringBuffer();
for (Iterator iter = parameters.entrySet().iterator(); iter
.hasNext();)
{
Entry element = (Entry) iter.next();
params.append(element.getKey().toString());
params.append("=");
params.append(URLEncoder.encode(element.getValue().toString(),
HttpRequestProxy.requestEncoding));
params.append("&");
}
if (params.length() > 0)
{
params = params.deleteCharAt(params.length() - 1);
}
URL url = new URL(reqUrl);
url_con = (HttpURLConnection) url.openConnection();
url_con.setRequestMethod("GET");
System.setProperty("sun.net.client.defaultConnectTimeout", String
.valueOf(HttpRequestProxy.connectTimeOut));// (单位:毫秒)jdk1.4换成这个,连接超时
System.setProperty("sun.net.client.defaultReadTimeout", String
.valueOf(HttpRequestProxy.readTimeOut)); // (单位:毫秒)jdk1.4换成这个,读操作超时
// url_con.setConnectTimeout(5000);//(单位:毫秒)jdk
// 1.5换成这个,连接超时
// url_con.setReadTimeout(5000);//(单位:毫秒)jdk 1.5换成这个,读操作超时
url_con.setDoOutput(true);
byte[] b = params.toString().getBytes();
url_con.getOutputStream().write(b, 0, b.length);
url_con.getOutputStream().flush();
url_con.getOutputStream().close();
InputStream in = url_con.getInputStream();
BufferedReader rd = new BufferedReader(new InputStreamReader(in,
recvEncoding));
String tempLine = rd.readLine();
StringBuffer temp = new StringBuffer();
String crlf=System.getProperty("line.separator");
while (tempLine != null)
{
temp.append(tempLine);
temp.append(crlf);
tempLine = rd.readLine();
}
responseContent = temp.toString();
rd.close();
in.close();
}
catch (IOException e)
{
logger.error("网络故障", e);
}
finally
{
if (url_con != null)
{
url_con.disconnect();
}
}
return responseContent;
}
/**
* <pre>
* 发送不带参数的GET的HTTP请求
* </pre>
*
* @param reqUrl HTTP请求URL
* @return HTTP响应的字符串
*/
public static String doGet(String reqUrl, String recvEncoding)
{
HttpURLConnection url_con = null;
String responseContent = null;
try
{
StringBuffer params = new StringBuffer();
String queryUrl = reqUrl;
int paramIndex = reqUrl.indexOf("?");
if (paramIndex > 0)
{
queryUrl = reqUrl.substring(0, paramIndex);
String parameters = reqUrl.substring(paramIndex + 1, reqUrl
.length());
String[] paramArray = parameters.split("&");
for (int i = 0; i < paramArray.length; i++)
{
String string = paramArray[i];
int index = string.indexOf("=");
if (index > 0)
{
String parameter = string.substring(0, index);
String value = string.substring(index + 1, string
.length());
params.append(parameter);
params.append("=");
params.append(URLEncoder.encode(value,
HttpRequestProxy.requestEncoding));
params.append("&");
}
}
params = params.deleteCharAt(params.length() - 1);
}
URL url = new URL(queryUrl);
url_con = (HttpURLConnection) url.openConnection();
url_con.setRequestMethod("GET");
System.setProperty("sun.net.client.defaultConnectTimeout", String
.valueOf(HttpRequestProxy.connectTimeOut));// (单位:毫秒)jdk1.4换成这个,连接超时
System.setProperty("sun.net.client.defaultReadTimeout", String
.valueOf(HttpRequestProxy.readTimeOut)); // (单位:毫秒)jdk1.4换成这个,读操作超时
// url_con.setConnectTimeout(5000);//(单位:毫秒)jdk
// 1.5换成这个,连接超时
// url_con.setReadTimeout(5000);//(单位:毫秒)jdk 1.5换成这个,读操作超时
url_con.setDoOutput(true);
byte[] b = params.toString().getBytes();
url_con.getOutputStream().write(b, 0, b.length);
url_con.getOutputStream().flush();
url_con.getOutputStream().close();
InputStream in = url_con.getInputStream();
BufferedReader rd = new BufferedReader(new InputStreamReader(in,
recvEncoding));
String tempLine = rd.readLine();
StringBuffer temp = new StringBuffer();
String crlf=System.getProperty("line.separator");
while (tempLine != null)
{
temp.append(tempLine);
temp.append(crlf);
tempLine = rd.readLine();
}
responseContent = temp.toString();
rd.close();
in.close();
}
catch (IOException e)
{
logger.error("网络故障", e);
}
finally
{
if (url_con != null)
{
url_con.disconnect();
}
}
return responseContent;
}
/**
* <pre>
* 发送带参数的POST的HTTP请求
* </pre>
*
* @param reqUrl HTTP请求URL
* @param parameters 参数映射表
* @return HTTP响应的字符串
*/
public static String doPost(String reqUrl, Map parameters,
String recvEncoding)
{
HttpURLConnection url_con = null;
String responseContent = null;
try
{
StringBuffer params = new StringBuffer();
for (Iterator iter = parameters.entrySet().iterator(); iter
.hasNext();)
{
Entry element = (Entry) iter.next();
params.append(element.getKey().toString());
params.append("=");
params.append(URLEncoder.encode(element.getValue().toString(),
HttpRequestProxy.requestEncoding));
params.append("&");
}
if (params.length() > 0)
{
params = params.deleteCharAt(params.length() - 1);
}
URL url = new URL(reqUrl);
url_con = (HttpURLConnection) url.openConnection();
url_con.setRequestMethod("POST");
System.setProperty("sun.net.client.defaultConnectTimeout", String
.valueOf(HttpRequestProxy.connectTimeOut));// (单位:毫秒)jdk1.4换成这个,连接超时
System.setProperty("sun.net.client.defaultReadTimeout", String
.valueOf(HttpRequestProxy.readTimeOut)); // (单位:毫秒)jdk1.4换成这个,读操作超时
// url_con.setConnectTimeout(5000);//(单位:毫秒)jdk
// 1.5换成这个,连接超时
// url_con.setReadTimeout(5000);//(单位:毫秒)jdk 1.5换成这个,读操作超时
url_con.setDoOutput(true);
byte[] b = params.toString().getBytes();
url_con.getOutputStream().write(b, 0, b.length);
url_con.getOutputStream().flush();
url_con.getOutputStream().close();
InputStream in = url_con.getInputStream();
BufferedReader rd = new BufferedReader(new InputStreamReader(in,
recvEncoding));
String tempLine = rd.readLine();
StringBuffer tempStr = new StringBuffer();
String crlf=System.getProperty("line.separator");
while (tempLine != null)
{
tempStr.append(tempLine);
tempStr.append(crlf);
tempLine = rd.readLine();
}
responseContent = tempStr.toString();
rd.close();
in.close();
}
catch (IOException e)
{
logger.error("网络故障", e);
}
finally
{
if (url_con != null)
{
url_con.disconnect();
}
}
return responseContent;
}
/**
* @return 连接超时(毫秒)
* @see com.hengpeng.common.web.HttpRequestProxy#connectTimeOut
*/
public static int getConnectTimeOut()
{
return HttpRequestProxy.connectTimeOut;
}
/**
* @return 读取数据超时(毫秒)
* @see com.hengpeng.common.web.HttpRequestProxy#readTimeOut
*/
public static int getReadTimeOut()
{
return HttpRequestProxy.readTimeOut;
}
/**
* @return 请求编码
* @see com.hengpeng.common.web.HttpRequestProxy#requestEncoding
*/
public static String getRequestEncoding()
{
return requestEncoding;
}
/**
* @param connectTimeOut 连接超时(毫秒)
* @see com.hengpeng.common.web.HttpRequestProxy#connectTimeOut
*/
public static void setConnectTimeOut(int connectTimeOut)
{
HttpRequestProxy.connectTimeOut = connectTimeOut;
}
/**
* @param readTimeOut 读取数据超时(毫秒)
* @see com.hengpeng.common.web.HttpRequestProxy#readTimeOut
*/
public static void setReadTimeOut(int readTimeOut)
{
HttpRequestProxy.readTimeOut = readTimeOut;
}
/**
* @param requestEncoding 请求编码
* @see com.hengpeng.common.web.HttpRequestProxy#requestEncoding
*/
public static void setRequestEncoding(String requestEncoding)
{
HttpRequestProxy.requestEncoding = requestEncoding;
}
public static void main(String[] args)
{
Map map = new HashMap();
map.put("actionType", "1");
// map.put("issueId", "33");
String temp = HttpRequestProxy.doPost("http://192.168.0.99/AgentPortal/autoHandler", map, "GBK");
System.out.println("返回的消息是:"+temp);
}
}
文章来源:
http://blog.163.com/ccbobo_cat/blog/static/320994622009616102329953
posted @
2009-07-16 10:23 C.B.K 阅读(1803) |
评论 (1) |
编辑 收藏
/*
下面的程序说明了怎样实现对象序列化和反序列化。它由实例化一个MyClass类的对象开始。该对象有三个实例变量,它们的类型分别是String,int和double。这是我们希望存储和恢复的信息。
FileOutputStream被创建,引用了一个名为“serial”的文件。为该文件流创建一个ObjectOutputStream。ObjectOutputStream 的writeObject( )方法用来序列化对象。对象的输出流被刷新和关闭。
然后,引用名为“serial”的文件创建一个FileInputStream类并为该文件创建一个ObjectInputStream类。ObjectInputStream 的readObject( )方法用来反序列化对象。然后对象输入流被关闭。
注意MyClass被定义成实现Serializable接口。如果不这样做,将会引发一个NotSerializableException异常。试图做一些把MyClass实例变量声明成transient的实验。那些数据在序列化过程中不被保存
*/
import java.io.*;
class MyClass implements Serializable{
String s;
int i;
double d;
public MyClass (String s,int i,double d){
this.s = s;
this.i = i;
this.d = d;
}
public String toString(){
return "s=" + s + "; i=" + i + "; d=" + d;
}
}
class SerializationDemo{
public static void main(String[] args){
//Object serialization.
try{
MyClass object1 = new MyClass("Evan",9,9.9e10);
System.out.println("object1 : " +object1);
FileOutputStream fos = new FileOutputStream("serial");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(object1);
oos.flush();
oos.close();
}catch(Exception e){
System.out.println("Exception during serialization :" + e);
System.exit(0);
}
//Object deserialization.
try{
MyClass object2 ;
FileInputStream fis = new FileInputStream("serial");
ObjectInputStream ois = new ObjectInputStream(fis);
object2 = (MyClass)ois.readObject();
ois.close();
System.out.println("object2 : " +object2);
}catch(Exception e){
System.out.println("Exception during serialization :" + e);
System.exit(0);
}
}
}
文章来源:
http://blog.163.com/ccbobo_cat/blog/static/320994622009616101541196
posted @
2009-07-16 10:16 C.B.K 阅读(168) |
评论 (0) |
编辑 收藏
Java的serialization提供了一种持久化对象实例的机制。当持久化对象时,可能有一个特殊的对象数据成员,我们不想
用serialization机制来保存它。为了在一个特定对象的一个域上关闭serialization,可以在这个域前加上关键字transient。
transient是Java语言的关键字,用来表示一个域不是该对象串行化的一部分。当一个对象被串行化的时候,transient型变量的值不包括在串行化的表示中,然而非transient型的变量是被包括进去的。
文章来源:
http://blog.163.com/ccbobo_cat/blog/static/3209946220096161094144
posted @
2009-07-16 10:09 C.B.K 阅读(152) |
评论 (0) |
编辑 收藏
匹配中文字符的正则表达式: [\u4e00-\u9fa5]
匹配双字节字符(包括汉字在内): [^\x00-\xff]
应用:计算字符串的长度(一个双字节字符长度计2,ASCII字符计1)
String.prototype.len=function(){return this.replace([^\x00-\xff]/g,"aa").length;}
匹配空行的正则表达式: \n[\s| ]*\r
匹配HTML标记的正则表达式: /<(.*)>.*<\/>|<(.*) \/>/
匹配首尾空格的正则表达式: (^\s*)|(\s*$)
应用:javascript中没有像vbscript那样的trim函数,我们就可以利用这个表达式来实现,如下:
String.prototype.trim = function() {
return this.replace(/(^\s*)|(\s*$)/g, "");
}
利用正则表达式分解和转换IP地址:
下面是利用正则表达式匹配IP地址,并将IP地址转换成对应数值的javascript程序:
function IP2V(ip) {
re=/(\d+)\.(\d+)\.(\d+)\.(\d+)/g //匹配IP地址的正则表达式
if(re.test(ip)) {
return RegExp.*Math.pow(255,3))+RegExp.*Math.pow(255,2))+RegExp.*255+RegExp.*1
}
else {
throw new Error("Not a valid IP address!")
}
}
不过上面的程序如果不用正则表达式,而直接用split函数来分解可能更简单,程序如下:
var ip="10.100.20.168"
ip=ip.split(".")
alert("IP值是:"+(ip[0]*255*255*255+ip[1]*255*255+ip[2]*255+ip[3]*1))
匹配Email地址的正则表达式: \w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*
匹配网址URL的正则表达式: http://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?
利用正则表达式去除字串中重复的字符的算法程序:
var s="abacabefgeeii"
var s1=s.replace(/(.).*/g,"")
var re=new RegExp("["+s1+"]","g")
var s2=s.replace(re,"")
alert(s1+s2) //结果为:abcefgi
用正则表达式从URL地址中提取文件名的javascript程序,如下结果为page1
s="http://www.9499.net/page1.htm"
s=s.replace(/(.*\/)([^\.]+).*/ig,"")
alert(s)
利用正则表达式限制网页表单里的文本框输入内容:
用正则表达式限制只能输入中文:
onkeyup="value=value.replace(/[^\u4E00-\u9FA5]/g,'')"
onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\u4E00-\u9FA5]/g,''))"
用正则表达式限制只能输入全角字符:
onkeyup="value=value.replace(/[^\uFF00-\uFFFF]/g,'')"
onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\uFF00-\uFFFF]/g,''))"
用正则表达式限制只能输入数字:
onkeyup="value=value.replace(/[^\d]/g,'')
"onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\d]/g,''))"
用正则表达式限制只能输入数字和英文:
onkeyup="value=value.replace(/[\W]/g,'')
"onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\d]/g,''))"
文章来源:
http://blog.163.com/ccbobo_cat/blog/static/32099462200961005220547
posted @
2009-07-10 12:52 C.B.K 阅读(206) |
评论 (0) |
编辑 收藏
ant手册中的ant配置classpath采用classpath标签,可是我发现这样配置总是不好用,还是直接用path可以使用
设置classpath的方法有多种
<path id="project.classpath">
1<pathelement path="${basedir}/lib/aa.jar"/>
2<pathelement location="aa.jar"/>与1的区别在于location可以去当前路径,当然可以使用绝对路径
3<filelist id="file" dir="${basedir}/lin">
<file name="a.jar"/>
<file name="d:lib/b.jar"/>
</filelist>
4<fileset dir="d:/lib">
<include name="**/*.jar"/>
</fileset>
5手册上说了dirset也好用,但是我测试了还是不要用的
</path>
下面说classpath的使用
样例如下
<javac scdir="./src" destdir="./classes">
<classpath refid="project.classpath"/>
</javac>
下面是比较四种方式的优缺点
第一种调用的需要设置绝对路径适合第三方jar包
第二种则适合jar包和build.xml文件在同一目录下的情况,但是我觉得两个文件放在一起本身就不合理,估计是用的情况不多。
前两个都是设置单个jar包
第三种是一个文件集合适合引入不同路径的jar包,但是需要输入每个jar包的名字,比较繁琐,适合于jar包属于不同位置,比较分散但是不多的情况
第四种是一个文件夹,可以采用匹配模式来引入,这个适合在同一个文件夹下,文件名字比较多的情况下
文章来源:
http://blog.163.com/ccbobo_cat/blog/static/32099462200961051533899
posted @
2009-07-10 05:16 C.B.K 阅读(1641) |
评论 (0) |
编辑 收藏
ant的构建文件中,有很多核心类型,这些核心类型都是XXXSet的形式,主要有以下几个:PatternSet、DirSet、FileSet、PropertySet、ZipFileSet等。说下前三个的功能就应该可以举一反三了。
1.PatternSet
即模式集合。顾名思义,就是定义一个模式,他可以用来指定一个文件集合。常常可以被外部的target引用,复用性很强。有includes、
includesfile、excludes、excludesfile属性。每个属性里面还可以嵌套name、if、unless等类型。
2.DirSet 即目录集合。用来定义目录的集合。有dir、casesensitive、followsymlinks和PatternSet也有的那4个属性。上面说过PatternSet可以很好的复用。下面就是一个例子:
- <dirset dir="${build.dir}">
- <patternset id="non.test.classes">
- <include name="apps/**/classes"/>
- <exclude name="apps/**/*Test*"/>
- </patternset>
- </dirset>
<dirset dir="${build.dir}">
<patternset id="non.test.classes">
<include name="apps/**/classes"/>
<exclude name="apps/**/*Test*"/>
</patternset>
</dirset>
这是用patternset来定义DirSet的模式,这个模式还可以在外部引用。如:
- <dirset dir="{build.dir}">
- <patternset refid="non.test.classes"/>
- </dirset>
<dirset dir="{build.dir}">
<patternset refid="non.test.classes"/>
</dirset>
上面定义了一个名为non.test.classes的PatternSet,现在就可以引用他了。refid即reference ID.
3.FileSet即文件集合,他的内部属性与DirSet几乎一样,只是多了一个file和defaultexcludes。和dirset一样,经常
嵌入patternset来定义文件集合;但是也有另外一个很常用的类型,叫selector,它并不是一个真正的类型或元素,只是一种、一类类型的统
称。如contains、date、depend、depth、different、filename、present、containsregexp、
size、type等。
文章来源:
http://blog.163.com/ccbobo_cat/blog/static/3209946220096105521217
posted @
2009-07-10 05:05 C.B.K 阅读(424) |
评论 (0) |
编辑 收藏
第一种方法:
mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
-> ON <dbname>.*
-> TO <username>@<host name>
-> IDENTIFIED BY '<password>';
where <dbname> is the name of the database you are tyring to
connect to, <username> is the username of the user trying to
connect to the database, <host name> the name of the host (in
your case the XXX host) and <password> the password of the user.
第二种方法:
通过客户端软件设置用户的主机以及权限,
文章来源:
http://blog.163.com/ccbobo_cat/blog/static/32099462200952925050579
posted @
2009-06-29 14:51 C.B.K 阅读(1555) |
评论 (0) |
编辑 收藏
一、什么是条件变量
与互斥锁不同,条件变量是用来等待而不是用来上锁的。条件变量用来自动阻塞一个线程,直到某特殊情况发生为止。通常条件变量和互斥锁同时使用。
条件变量使我们可以睡眠等待某种条件出现。条件变量是利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:一个线程等待"条件变量的条件成立"而挂起;另一个线程使"条件成立"(给出条件成立信号)。
条
件的检测是在互斥锁的保护下进行的。如果一个条件为假,一个线程自动阻塞,并释放等待状态改变的互斥锁。如果另一个线程改变了条件,它发信号给关联的条件
变量,唤醒一个或多个等待它的线程,重新获得互斥锁,重新评价条件。如果两进程共享可读写的内存,条件变量可以被用来实现这两进程间的线程同步。
使用条件变量之前要先进行初始化。可以在单个语句中生成和初始化一个条件变量如:
pthread_cond_t my_condition=PTHREAD_COND_INITIALIZER;(用于进程间线程的通信)。
也可以利用函数pthread_cond_init动态初始化。
二、条件变量函数
1.
名称: |
pthread_cond_init |
目标: |
条件变量初始化 |
头文件: |
#include < pthread.h> |
函数原形: |
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr); |
参数: |
cptr 条件变量
attr 条件变量属性 |
返回值: |
成功返回0,出错返回错误编号。 |
pthread_cond_init函数可以用来初始化一个条件变量。他使用变量attr所指定的属性来初始化一个条件变量,如果参数attr为空,那么它将使用缺省的属性来设置所指定的条件变量。
2.
名称: |
pthread_cond_destroy |
目标: |
条件变量摧毁 |
头文件: |
#include < pthread.h> |
函数原形: |
int pthread_cond_destroy(pthread_cond_t *cond); |
参数: |
cptr 条件变量 |
返回值: |
成功返回0,出错返回错误编号。 |
pthread_cond_destroy函数可以用来摧毁所指定的条件变量,同时将会释放所给它分配的资源。调用该函数的进程也并不要求等待在参数所指定的条件变量上。
3.
名称: |
pthread_cond_wait/pthread_cond_timedwait |
目标: |
条件变量等待 |
头文件: |
#include < pthread.h> |
函数原形: |
int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex);
int pthread_cond_timedwait(pthread_cond_t *cond,pthread_mutex_t mytex,const struct timespec *abstime); |
参数: |
cond 条件变量
mutex 互斥锁 |
返回值: |
成功返回0,出错返回错误编号。 |
第一个参数*cond是指向一个条件变量的指针。第二个参数*mutex则是对相关的互斥锁的指针。函数pthread_cond_timedwait函数类型与函数pthread_cond_wait,区别在于,如果达到或是超过所引用的参数*abstime,它将结束并返回错误ETIME.pthread_cond_timedwait函数的参数*abstime指向一个timespec结构。该结构如下:
typedef struct timespec{
time_t tv_sec;
long tv_nsex;
}timespec_t;
3.
名称: |
pthread_cond_signal/pthread_cond_broadcast |
目标: |
条件变量通知 |
头文件: |
#include < pthread.h> |
函数原形: |
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond); |
参数: |
cond 条件变量 |
返回值: |
成功返回0,出错返回错误编号。 |
参数*cond是对类型为pthread_cond_t 的一个条件变量的指针。当调用pthread_cond_signal时一个在相同条件变量上阻塞的线程将被解锁。如果同时有多个线程阻塞,则由调度策略确定接收通知的线程。如果调用pthread_cond_broadcast,则将通知阻塞在这个条件变量上的所有线程。一旦被唤醒,线程仍然会要求互斥锁。如果当前没有线程等待通知,则上面两种调用实际上成为一个空操作。如果参数*cond指向非法地址,则返回值EINVAL。
下面是一个简单的例子,我们可以从程序的运行来了解条件变量的作用。
#include <pthread.h> #include <stdio.h> #include <stdlib.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;/*初始化互斥锁*/ pthread_cond_t cond = PTHREAD_COND_INITIALIZER;/*初始化条件变量*/
void *thread1(void *); void *thread2(void *);
int i=1; int main(void) { pthread_t t_a; pthread_t t_b;
pthread_create(&t_a,NULL,thread2,(void *)NULL);/*创建进程t_a*/ pthread_create(&t_b,NULL,thread1,(void *)NULL); /*创建进程t_b*/ pthread_join(t_b, NULL);/*等待进程t_b结束*/ pthread_mutex_destroy(&mutex); pthread_cond_destroy(&cond); exit(0); }
void *thread1(void *junk) { for(i=1;i<=9;i++) { pthread_mutex_lock(&mutex);/*锁住互斥量*/ if(i%3==0) pthread_cond_signal(&cond);/*条件改变,发送信号,通知t_b进程*/ else printf("thead1:%d\n",i); pthread_mutex_unlock(&mutex);/*解锁互斥量*/
sleep(1); }
}
void *thread2(void *junk) { while(i<9) { pthread_mutex_lock(&mutex);
if(i%3!=0) pthread_cond_wait(&cond,&mutex);/*等待*/ printf("thread2:%d\n",i); pthread_mutex_unlock(&mutex);
sleep(1); }
} |
程序创建了2个新线程使他们同步运行,实现进程t_b打印20以内3的倍数,t_a打印其他的数,程序开始线程t_b不满足条件等待,线程t_a运行使a循环加1并打印。直到i为3的倍数时,线程t_a发送信号通知进程t_b,这时t_b满足条件,打印i值。
下面是运行结果:
#cc –lpthread –o cond cond.c
#./cond
thread1:1
thread1:2
thread2:3
thread1:4
thread1:5
thread2:6
thread1:7
thread1:8
thread2:9
文章来源:
http://blog.163.com/ccbobo_cat/blog/static/3209946220095235658763
posted @
2009-06-23 17:07 C.B.K 阅读(287) |
评论 (0) |
编辑 收藏
工具:grub4dos0.4.2(想要的给我发信,我发给你,loveitdoit@163.com)
文件:fedora7.0映像文件,可在网上下载。
过程:
1.解压缩grub4dos0.4.2,把里面的 grldr和menu.lst,文件复制到c盘根目录下。
2.fedora7.0映像文件不必解压,必须放在fat32的分区里。把里面的isolinux目录下
的VMLINUZ、INITRD.IMG解压到c盘根目录下。
3.在c:\下找到menu.lst,用记事本打开并修改,删除其他命令,添加以下命令!
title Linux System Install
kernel (hd0,0)/vmlinuz
initrd (hd0,0)/initrd.img
4.修改c:\boot.ini文件,在最后面添加c:\grldr="Start GRUB"并保存即可。
5.重起系统,选择Start GRUB,开始安装。
文章来源:
http://blog.163.com/ccbobo_cat/blog/static/3209946220095234437396
posted @
2009-06-23 16:05 C.B.K 阅读(137) |
评论 (0) |
编辑 收藏
花了半天时间研究了下下MYSQL的备份实现,发现其是在MY.CNF(MY.INI)配置文件中作的设置,直接设置服务器唯一性ID号加上其它的附加设
置,则可作为一台MASTER,而在
SLAVE机上,也只需要在配置文件中设置一下连接MASTER所需的参数即可,如果在MASTER里也加上连到SLAVE机的参数,则就是双向备份
了~~不过,这些连接参数中用到的账号需要注意权限的设置,否则会搞半天没反就急死你迪。。。
我在WIN上和LINUX上各装了MYSQL5,下面是它们的配置:
WIN(172.22.33.33)下的MASTER(由于我改了端口3327所以下面多加了个端口方面的特殊处理了)的配置(my.ini):(**一定要在mysqld配置段中配置,不象PHP,APACHE可以随便找个方便的地方配的,注意哈!!)
[mysqld]
#master 设置
server-id=1
log-bin=c:/masterlog
binlog-do-db=db5
#实现双机备份段,给MASTER同时加上SLAVE段,可选哈,如果不选,那就是WIN到LIN的主从备份
master-host=172.22.1.37
master-user=backup2
master-password=backup2
master-port=3306
master-connect-retry=60
replicate-do-db=db5
数据库中加一个账号:
GRANT FILE,REPLICATION SLAVE,REPLICATION CLIENT,SUPER ON *.*
TO [email=backup@]backup@'172.22.1.37'[/email] IDENTIFIED by 'backup';
这个权限表示,这个backup账号只能由从备份机172.22.1.37访问只能用来进行备份操作
LINUX(172.22.1.37)下的SLAVE机的配置(把安装目录里找到的任意一个*.cnf拷到/etc/my.cnf下进行修改):
server-id=2
#如果不需要双向备份下面两行可以不要
#否则还要加一个数据库用户账号
/*
GRANT FILE,REPLICATION SLAVE,REPLICATION CLIENT,SUPER ON *.*
TO [email=backup2@]backup2@'172.22.33.33'[/email] IDENTIFIED by 'backup2';
*/
log-bin=./masterlog
binlog-do-db=db5
#---------------------------------------
master-host=172.22.33.33
master-user=backup
master-password=backup
master-port=3327
master-connect-retry=60
replicate-do-db=db5
由于只是大概的弄了一下,特别是在数据库用户方面没有作仔细试验:),可能会有所不太准确的地方,还有就是,上面测试用到的数据库一定要是已经建立好并且
结构相同的,两台机子都重启后会进行检查,如果出现找不到或者检查到结构不同,会报错,最好就是在创建空数据库时或初始时安装两个一样的数据库后就建立好
关系,对于不同版本的MYSQL,官方说明也可以同步,但想一想,把MYSQL5 的数据备份到4中去丢失5的特性也没什么意义吧。。
文章来源:
http://blog.163.com/ccbobo_cat/blog/static/32099462200952335921779
posted @
2009-06-23 15:59 C.B.K 阅读(213) |
评论 (0) |
编辑 收藏
【第一篇】
首先、确定你自己的英语水平。中国大学毕业生的通病是,书面阅读还可以,口语不行,听力很差,书写凑合。但每个人具体情况又都不一样,有人阅读专业书一目
十行,但读报纸很费劲。有人听新闻可以,听别的不行。你必须首先了解自己,然后针对你的情况对症下药。这种评估工作最好找英语好的人帮你做,如果不方便,
只能自己评自己,就要尽量做到客观。 其次、确定自己的发音水平。我有个朋友对我说他的发音没问题,可实际上他说得很多词我都听不懂。你学的是英国音还
是美国音都无所谓,反正最终从你嘴里出来的肯定是中国音。最重要的是发音要合理。英语每一个单词都有自己的念法,你不能凭空想象。比如,有人把
RESUME读做RE-'SOOM,这样,别人说RE-SIU-'MAY,你不知道是什么。你念RE-'SOOM,别人也听不懂。再次、确定自己的英语学
习目标。我这里仅把口语交流做为目标。最后、开始学习。
1、口语学习的关键是要模仿人家的说话。这包括语音和语调两部分。中国英语教学重视语调的很少,尽管很多时候语调可能比语音更重要。
2、买一台录音机,找一合磁带。根据你的水平,可以选择新概念第二或第三册,也可以到图书馆借一套有书和磁带的小故事集。注意:一定要有书,故事篇幅不能太长,生词量要小,过于简单没有关系。我倾向于使用故事,而不是对话或新闻听力材料。
3、进行跟读训练。放磁带,看着书,搞明白每一个单词的意思,理解整个故事情节。然后,放一句,暂停,学着人家读一句,然后,放下一句,暂停,再学一句,继续。
4、跟读过程中要注意的几点:
(1)一定要尽力模仿发音和语调,越象越好。
(2)开始时速度可以比较慢,要逐步使自己跟上人家的速度。
(3)中间可以回倒重放,但我倾向于让大家完成一小段后再回去重来。
5、同步阅读。当你对文章发音、语调完全掌握之后,就要在放录音的同时同步跟读。争取让自己的声音与他完全重合。注意语调和语音。如果中间有结巴的地方也不要紧,继续读下去,然后再回来重读。
6、关掉录音机,朗诵课文。注意使用学到的语音语调。带滚瓜烂熟之后,可以进入下一篇课文。
这样,一两个月之后,当你“精读”过五到十篇约一千字篇幅的文章之后,你会发现你的英语发音和听力有了明显的进步。再配合其他学习,如与人聊天,看电视,听广播,等等,口语水平会得到显著提高。
【第二篇】
英语作为一种工具,其实用性愈显重要。传统英语教育方法由于过于艰深化,以及盲目的应试模式使大部分的英语学习者学了几年甚至数十年,却仍然处于听不懂开不了口的尴尬境地。那么究竟如何才能在比较短的时间里快速提高口语水平,让她真正为你所用呢?
西方最新流行一种外语学习理论,即口语提高的最好方式就是采用短期突破法。从下面的公式中,就可以看出,口语短期突破的方法是很有效的。
口语提高速度定律=说英语时间/说中文时间Speed of learning English=Speaking English/Speaking Chinese ( in a period of time)
比如,在给定的一天时间内(16小时),学生A练习英语口语的时间为14小时,说中文的时间为2小时,两者的比例为7:1;学生B练习口语的时间为2
小时英语,说中文的时间为14小时。比例为1:7。如此一来,学生A比学生B说英语的比例大49倍。
我们认为:这一理论其实就是对语言学习规律一次很好的回归,语言的核心是使用者能够随时随地地使用它。你用的时间越长,你就越熟练,这里我们说的使用
就是“说”,用嘴巴表达出来,而不是用眼睛和脑子去看和死记。如果你能够在一段时间内的大部分时间里坚持持续使用英语而不是中文进行表达,把学习英语的任
务转化成母语似的说话习惯,你就完全可以在很短的时间内有效掌握一口流利的英语口语。
当然现实情况却是:很多人并没有这样的勇气和能力去坚持使用一个完全不熟悉的语言进行日常的交流!所以选用一套优秀的教材和相应的工具就显得异常重要了,这种教材应该具备以下特点才能帮助你克服困难:
1、能够随时随地学习,让你很容易就接触到英语;
2、能够让你脱离书本,完全浸在英语环境里;
3、内容应该精挑细选,具备典型性和代表性,帮助你在短时间内掌握精华内容,从而建立起长期学习的信心和基本能力。
同时你应该注意培养自己的自信,学会勇敢犯错误,克服恐惧的心理障碍。其实这种心理障碍是成人自己加给自己的,为什么我们小时候学母语这么自然容易,就是因为那个时候不知道什么是丢脸。所以我们应该象小时候那样暂时忘却丢脸,勇敢地去丢脸!
【第三篇】
想提高英语口语水平,首先要在语音上下功夫:)~
下面是些方法,你可以根据自己的学习方式掌握:)~
1.其次,要有大量的阅读和听力做基础。在读和听的过程中,积累了词汇,掌握了句型,熟悉了用英语表达思想的方式,最重要的是培养了语感。
2.同时,学英语口语也需要用多种办法:如大声朗读英语对话和文章,朗读各种句型的例句和口语中最常用的句子,背诵文章及演讲,与会英语的人练口语,当
然,最好与以英语为母语的人练口语。事实上,自言自语亦是练习口语的有效的方法之一。如果你把自己说的英语给录制下来,听听自己的录音,若有问题,再加以
改正,效果就会更好。
3.说英语还要有胆量。如果你能在说不太出口,或是说不好的情况下,大胆地说。说上一段时间后,突然有一天你会自如、清楚地表达自己的思想。有了大胆说的精神,你才能闯过口语的难关。
4.只会学英语,而不能尽快地去用,那就永远也学不好英语。在学英语的过程中,要始终寻找机会说英语。比如说,你周围有几个喜欢说英语的朋友,大家在一起
就要用英语来交谈。这种交谈有利于每个人的英语学习,因为大家都有机会运用自己已掌握的英语知识来交流思想,巩固了已学的知识,并把知识转化成技能,同
时,还能从别人那儿学到新的东西。要想学好英语口语就要多说。
5.能同以英语为母语的人说英语是最佳方法。在国内学英语缺乏环境,看电影学英语口语是弥补环境不足的好方法。英语电影是一部英语国家的生活、文化、风俗
等一切的百科全书,是最全的英语口语百科全书。大量地看英文电影就是你彻底攻克英语“听”和“说”的法宝。英语电影把你带入了一个新的世界中去。你在电影
中,学到了英语口语的语汇、短语、句子结构,以及表达各种内容的说法。你要做的就是把自己想像成电影中的一个角色,在经历着自己的生活,又在经历着其他人
的生活。总之,看一部电影比在美国生活一天还好,看电影也能学到地道的英语口语。
【第四篇】
当代社会是个开放社会,信息社会,人们越来越重视交际,而我国改革开放的成功也日益提高了我国在世界上的地位,我们与世界各国交流的领域越来越广了,没有出众的英语口语表达将会寸步难行。
而要提高英语口语表达能力,就要先了解英语口语表达的过程是怎样发生的。大家知道,语言是思维的外壳。口语表达的过程,实际上是一个复杂的心理和生理过程,是思维借助词语按一定句式迅速转换为有声言语的过程。因此,口语能力的强弱取决于:
1、思维能力的强弱,特别是与口语有关的思维的条理性、敏锐性与灵活性,这是关键。
2、准确、迅速地组织言语(选词、造句、组段、构篇)能力的强弱,这是基础。
3、运用语言的能力的强弱,这是前提。
根据口语表达循序渐进的一般规律,口语训练的重点应是培养敏锐的思维和强烈的语感。具体包括:
1、语音。学会科学发声方法,能用准确、响亮、流畅的英语进行口头表达。
2、语调。能借助声音高低升降、抑扬顿挫的变化来表达复杂的感情,掌握停连和轻重、抑扬和明暗、快慢和松紧等一般的朗读技巧。
3、词汇。能掌握比较丰富的口语词汇。
4、语脉。说话能做到有条有理、语言流畅、上下贯通、一脉相承。
5、语境。说话注意目的、对象、场合,合乎规定情景的要求,讲礼貌、有针对性。懂得口语修辞。在会话中有随机应变的能力。
此外,还要懂得口头言语的辅助手段--表情、姿势、动作等态势言语的运用。
由于书面语和口语是相互渗透、相互促进的,为提高口语的表现力,可在说话训练之前先进行一章朗读、朗诵训练。听和说是一个事物的两个方面,吸收、表达
两者不能偏废,所以口语训练体系中也应包括。通过以上训练,掌握一定的朗读朗诵技巧,培养准确、流利、有感情地朗读朗诵一般作品的能力,特别注意培养强烈
的语感。
3、听力训练
培养听的注意力、理解力、记忆力和辨析力,提高听知能力,养成良好的听的习惯。
4、口语表达基本方式训练
进行叙述、描述、评述、解说等口语表达基本方式的训练,培养内部言语向外部言语迅速转化的能力,结合进行语调、语脉的训练。
5、会话型言语训练
言语形式有会话型和独白型两类。会话是指两个以上的人围绕一个或几个话题一起说话的形式,如交谈、座谈、辩论、审讯等。会话时参加者是互为听、讲者
的,因此后面的发言常常受到前面发言的制约。另外,由于当面交谈,大量态势语代替了言语表达,会话者的言语结构往往不严谨、不完善,省略句较多。
可进行如下训练:通过交谈和辩论两种会话言语训练,了解它们的一般特点、注意事项,结合进行应变能力和礼貌用语的训练,从而在会话中有效地培养随机应变的能力。
6、独白型言语训练
独白是指一个人单独发言而其他人都作为听众的言语表达形式,如:讲故事、作报告、讲课、演讲、讲解员的解说等。独白言语一般不在进行过程中跟听众问答
交流,因此要求在事先要周密地了解听众的要求并系统地组织好发言内容和有关态势语。独白是一种高层次的言语形式。
可通过讲故事和演讲两种独白言语的训练,了解它们的一般特点、注意事项,结合进行运用态势语的训练,这类训练很有利于培养思维的条理性和连贯性。
7、即兴小品训练
即兴小品要求表演者按照规定的题目和要求,在规定的时间内,充分发挥自己的想象,不用或少用道具,通过言语和动作的表演,展现社会生活中的某个瞬间或片断,表达一个简单的主题。
严格地说,小品应该是话剧艺术表演训练的一种形式,但由于它具有综合的特点,对训练思维的创造性、敏捷性、条理性、言语表达的准确性、形象性、流畅
性,以及应变力,乃至姿势的综合运用等等,都有很大的好处,所以我们要想英语口语表达能力更上一个层次,这种形式的训练也要加以采用。
懂得了英语口语表达的规律,并不等于就有了一口流畅的英语表达口才,就好象读了介绍游泳的书并不等于一定会游泳一样,关键还是要在长期的时实践中持之
以恒地艰苦磨练。这种训练不同于我们平时常听常说的那种日常英语口语训练。日常的英语口语训练与之相比简单得多,所用的词汇量及话题所涉及的深度都是相当
有限的。而真正高层次的英语口语交际所需达到的流畅性、条理性、敏锐性和灵活性并不是常练一些日常用语就能达到的,其中用到的词汇量也因话题的深入和多样
而大大增加了。
所以,要想真正地提高英语口语,说一口流利而又有水平的交际英语,得有对英语口语表达感兴趣作为前提,懂得以上的规律,重视运用以上的训练步骤,加上
长期的艰苦训练,才会有成效,才会达到目的。听力训练,当然,在训练过程中,听和说是无法截然分开的。
因此,英语口语训练体系可按以下顺序安排:
1、语音训练
在学习英语语音知识的基础上加强语音训练,进行方音辨正练习。通过学习,打好英语语音知识,有一定的辨音能力,能用英语正确、清楚、响亮地表达。
2、朗读朗诵训练
进行呼吸、发声与共鸣训练,吐字纳音的训练,以及各种朗读朗诵技巧的训练,学会常用文体的朗读、朗诵,懂得在朗诵中恰当使用态势语
文章来源:
http://blog.163.com/ccbobo_cat/blog/static/3209946220095109201252
posted @
2009-06-10 09:20 C.B.K 阅读(91) |
评论 (0) |
编辑 收藏
[关键字]:java,design pattern,设计模式,《Java与模式》,Chain of Responsibility,责任链模式
[环境]:StarUML5.0 + JDK6
[作者]:Winty (wintys@gmail.com)
[正文]:
package pattern.chainofresponsibility;
/**
* 责任链模式:Chain of Responsibility
* @version 2009-5-9
* @author Winty(wintys@gmail.com)
*/
public class ChainOfResponsibilityTest{
public static void main(String[] args){
Handler handler1 = new ConcreteHandler1();
Handler handler2 = new ConcreteHandler2();
Handler handler3 = new ConcreteHandler3();
//设置责任链
handler3.setSuccessor(handler2);
handler2.setSuccessor(handler1);
//发送命令
handler3.handleRequest();
}
}
/**
*抽象处理者
*/
abstract class Handler{
protected Handler successor;
public Handler getSuccessor(){
return successor;
}
public void setSuccessor(Handler successor){
this.successor = successor;
}
public abstract void handleRequest();
}
/**
*具体处理者
*/
class ConcreteHandler1 extends Handler{
public void handleRequest(){
if(getSuccessor() != null){
System.out.print("Request passed:from class Concrete1");
System.out.println(" to class" + getSuccessor().getClass().getName());
getSuccessor().handleRequest();
}
else{
System.out.println("Request handled in ConcreteHandler1");
}
}
}
/**
*具体处理者
*/
class ConcreteHandler2 extends Handler{
public void handleRequest(){
if(getSuccessor() != null){
System.out.print("Request passed:from class Concrete2");
System.out.println(" to class " + getSuccessor().getClass().getName());
getSuccessor().handleRequest();
}
else{
System.out.println("Request handled in ConcreteHandler2");
}
}
}
/**
*具体处理者
*/
class ConcreteHandler3 extends Handler{
public void handleRequest(){
if(getSuccessor() != null){
System.out.print("Request passed:from class Concrete3");
System.out.println(" to class " + getSuccessor().getClass().getName());
getSuccessor().handleRequest();
}
else{
System.out.println("Request handled in ConcreteHandler3");
}
}
}
文章来源:
http://blog.163.com/ccbobo_cat/blog/static/320994622009410264843
posted @
2009-05-10 14:07 C.B.K 阅读(86) |
评论 (0) |
编辑 收藏
这么一个需求:同一台服务器上有两个应用,如
http://hostA:8080/services和
http://hostA:8080/admin外部访问时,需要从不同的域名访问,如
http://services.host.com和
http://admin.host.com一开始给他们这么一个比较简单的解决方案:
分别把services和admin两个应用,部署到不同的两个端口上,如
services ->
http://hostA:8081/admin ->
http://hostA:8082/接着在防火墙配两个公网IP,然后dns上把services.host.com和admin.host.com配置到这两个IP上。
当请求到达防火墙时,防火墙根据所访问的ip转发到hostA的对应端口上。
前
方用的防火墙是我们公司的Audemon
100,和公司的Audemon系统组的交流后得知,目前的防火墙版本不支持同时配置两个ip,要到六月底才能出版本支持。!@…%#%…%¥,晕倒,好
像这是很基本的功能来的吧,居然还不支持。没办法,此路不通。由于防火墙是不管域名的(因为域名资料是通过应用层传输的),那更别指望防火墙根据域名转发
了。
因此,我们只好提供了软件级的解决方案,让前方在Tomcat前加一个Apache 2.2,通过Apache的Virtual Host + AJP实现转发。
Apache的部分配置如下:
NameVirtualHost *:80
<VirtualHost *:80>
ServerName host1.com
ProxyPass / ajp://host1.com:8009/
ProxyPassReverse / ajp://host1.com:8009/
</VirtualHost>
<VirtualHost *:80>
ServerName host2.com
ProxyPass / ajp://host2.com:8019/
ProxyPassReverse / ajp://host2.com:8019/
</VirtualHost>
Tomcat也需要配置AJP Connector,如host1.com的配置
<Connector port=”8009″ enableLookups=”false” redirectPort=”8443″ protocol=”AJP/1.3″ />
这个方案相对于防火墙的硬件方案,性能上要差一些,但还是不错的。
另
外还有一种方案是通过iptables的domain module来实现,但这个domain
module好像是国内的某个高手写的,只更新到v0.02版本,并没有提交到iptables的标准里。虽然可以用而且性能比Apache的方案要高一
些,但是风险较大,而且配置麻烦(既要编译内核,又要配置iptables的rules),所以没有用这种方式。
文章来源:
http://blog.163.com/ccbobo_cat/blog/static/320994622009326115641438
posted @
2009-04-26 11:57 C.B.K 阅读(4201) |
评论 (0) |
编辑 收藏
随着访问量的不断提高,以及对响应速度的要求,进行负载均衡设置就显得非常必要了。公司的系统在最初设计的时候就已经考虑到了负载均衡的规划,www静态
服务器配置了两台,由于初期项目时间紧,并且访问量并不高,所以当时只用了一台,另一台在内网中,只是进行了同步,并为发挥出效用来。此次就是对负载均衡
的一个简单测试。
先介绍一下apache mod_proxy_balancer的几个配置规则(从网上找的):
将Apache作为LoadBalance前置机分别有三种不同的部署方式,分别是:
1 )轮询均衡策略的配置
进入Apache的conf目录,打开httpd.conf文件,在文件的末尾加入:
ProxyPass / balancer://proxy/ #注意这里以"/"结尾
<Proxy balancer://proxy>
BalancerMember http://192.168.6.37:6888/
BalancerMember http://192.168.6.38:6888/
</Proxy>
我们来观察上述的参数“ProxyPass / balancer://proxy/”,其中,“ProxyPass”是配置虚拟服务器的命令,“/”代表发送Web请求的URL前缀,如:http://myserver/或者http://myserver/aaa,这些URL都将符合上述过滤条件;“balancer://proxy/”表示要配置负载均衡,proxy代表负载均衡名;BalancerMember 及其后面的URL表示要配置的后台服务器,其中URL为后台服务器请求时的URL。以上面的配置为例,实现负载均衡的原理如下:
假设Apache接收到http://localhost/aaa请求,由于该请求满足ProxyPass条件(其URL前缀为“/”),该请求会被分发到后台某一个BalancerMember,譬如,该请求可能会转发到 http://192.168.6.37:6888/aaa进行处理。当第二个满足条件的URL请求过来时,该请求可能会被分发到另外一台BalancerMember,譬如,可能会转发到http://192.168.6.38:6888/。如此循环反复,便实现了负载均衡的机制。
2) 按权重分配均衡策略的配置
ProxyPass / balancer://proxy/ #注意这里以"/"结尾
<Proxy balancer://proxy>
BalancerMember http://192.168.6.37:6888/ loadfactor=3
BalancerMember http://192.168.6.38:6888/ loadfactor=1
</Proxy>
参数”loadfactor”表示后台服务器负载到由Apache发送请求的权值,该值默认为1,可以将该值设置为1到100之间的任何值。以上面的配置
为例,介绍如何实现按权重分配的负载均衡,现假设Apache收到http://myserver/aaa
4次这样的请求,该请求分别被负载到后台服务器,则有3次连续的这样请求被负载到BalancerMember为http://192.168.6.37:6888的服务器,有1次这样的请求被负载BalancerMember为http://192.168.6.38:6888后台服务器。实现了按照权重连续分配的均衡策略。
3) 权重请求响应负载均衡策略的配置
ProxyPass / balancer://proxy/ lbmethod=bytraffic #注意这里以"/"结尾
<Proxy balancer://proxy>
BalancerMember http://192.168.6.37:6888/ loadfactor=3
BalancerMember http://192.168.6.38:6888/ loadfactor=1
</Proxy>
参数“lbmethod=bytraffic”表示后台服务器负载请求和响应的字节数,处理字节数的多少是以权值的方式来表示的。
“loadfactor”表示后台服务器处理负载请求和响应字节数的权值,该值默认为1,可以将该值设置在1到100的任何值。根据以上配置是这么进行均
衡负载的,假设Apache接收到http://myserver/aaa请求,将请求转发给后台服务器,如果BalancerMember为http://192.168.6.37:6888后台服务器负载到这个请求,那么它处理请求和响应的字节数是BalancerMember为http://192.168.6.38:6888 服务器的3倍(回想(2)均衡配置,(2)是以请求数作为权重负载均衡的,(3)是以流量为权重负载均衡的,这是最大的区别)。
看明白了没有,根据不同的需要,可以按这三种方式进行配置。我按照第三种配置的,感觉上这种对于负载的均衡更全面合理。我的配置很简单,如下:
先配置均衡器:
<Proxy balancer://proxy>
BalancerMember ajp://127.0.0.1:8009/ loadfactor=1
BalancerMember http://192.168.10.6:8083/ loadfactor=1
</Proxy>
其中http://192.168.10.6:8083实际上是另外一个端口启动的apache,为了测试,它就简单的直接转发所有请求到tomcat。
对于上次的VirtualHost进行以下的修改即可:
<VirtualHost *:80>
ServerName www.test.com
DocumentRoot /www
DirectoryIndex index.html index.jsp
<Directory "/www">
Options Indexes FollowSymLinks
AllowOverride None
Order allow,deny
Allow from all
</Directory>
<Directory "/control">
Options Indexes FollowSymLinks
AllowOverride None
Order allow,deny
Allow from all
</Directory>
ProxyPass /nxt/images/ !
ProxyPass /nxt/js/ !
ProxyPass /nxt/css/ !
#ProxyPass / ajp://127.0.0.1:8009/
#ProxyPassReverse / ajp://127.0.0.1:8009/
ProxyPass / balancer://proxy/
ProxyPassReverse / balancer://proxy/
</VirtualHost>
注释掉之前的ajp转发,而配置成通过balancer去处理。
通过观察access log,的确有部分请求发送到了8083端口的apache上,而有部分是直接ajp转发到tomcat上了。对于更多的负载均衡的参数检测,待空了再做。
文章来源:
http://blog.163.com/ccbobo_cat/blog/static/32099462200932611555639
posted @
2009-04-26 11:56 C.B.K 阅读(149) |
评论 (0) |
编辑 收藏
一、集群和负载均衡的概念
(一)集群的概念
集群(Cluster)是由两台或多台节点机(服务器)构成的一种松散耦合的计算节点集合,为用
户提供网络服务或应用程序(包括数据库、Web服务和文件服务等)的单一客户视图,同时提供接近容错机的故障恢复能力。集群系统一般通过两台或多台节点服
务器系统通过相应的硬件及软件互连,每个群集节点都是运行其自己进程的独立服务器。这些进程可以彼此通信,对网络客户机来说就像是形成了一个单一系统,协
同起来向用户提供应用程序、系统资源和数据。除了作为单一系统提供服务,集群系统还具有恢复服务器级故障的能力。集群系统还可通过在集群中继续增加服务器
的方式,从内部增加服务器的处理能力,并通过系统级的冗余提供固有的可靠性和可用性。
(二)集群的分类
1、高性能计算科学集群:
以解决复杂的科学计算问题为目的的IA集群系统。是并行计算的基础,它可以不使用专门的由十至上万个独立处理器组成的并行超级计算机,而是采用通过高速
连接来链接的一组1/2/4
CPU的IA服务器,并且在公共消息传递层上进行通信以运行并行应用程序。这样的计算集群,其处理能力与真正超级并行机相等,并且具有优良的性价比。
2、负载均衡集群:
负载均衡集群为企业需求提供更实用的系统。该系统使各节点的负载流量可以在服务器集群中尽可能平均合理地分摊处理。该负载需要均衡计算的应用程序处理端
口负载或网络流量负载。这样的系统非常适合于运行同一组应用程序的大量用户。每个节点都可以处理一部分负载,并且可以在节点之间动态分配负载,以实现平
衡。对于网络流量也如此。通常,网络服务器应用程序接受了大量入网流量,无法迅速处理,这就需要将流量发送给在其它节点。负载均衡算法还可以根据每个节点
不同的可用资源或网络的特殊环境来进行优化。
3、高可用性集群:
为保证集群整体服务的高可用,考虑计算硬件和软件的容错性。如果高可用性群集中的某个节点发生了故障,那么将由另外的节点代替它。整个系统环境对于用户是一致的。
实际应用的集群系统中,这三种基本类型经常会发生混合与交杂。
(三)典型集群
科学计算集群:
1、Beowulf
当谈到 Linux
集群时,许多人的第一反映是 Beowulf。那是最著名的 Linux科学软件集群系统。实际上,它是一组适用于在 Linux
内核上运行的公共软件包的通称。其中包括流行的软件消息传递 API,如“消息传送接口”(MPI) 或“并行虚拟机”(PVM),对 Linux
内核的修改,以允许结合几个以太网接口、高性能网络驱动器,对虚拟内存管理器的更改,以及分布式进程间通信 (DIPC)
服务。公共全局进程标识空间允许使用 DIPC 机制从任何节点访问任何进程。
2、MOSIX
Beowulf类似于给系统安装的一个支持
集群的外挂软件,提供了应用级的集群能力。而MOSIX是彻底修改Linux的内核,从系统级提供了集群能力,它对应用而言是完全透明的,原有的应用程
序,可以不经改动,就能正常运行在MOSIX系统之上。集群中的任何节点都可以自由地加入和移除,来接替其它节点的工作,或是扩充系统。MOSIX
使用自适应进程负载均衡和内存引导算法使整体性能最大化。应用程序进程可以在节点之间实现迁移,以利用最好的资源,这类似于对称多处理器系统可以在各个处
理器之间切换应用程序。由于MOSIX通过修改内核来实现集群功能,所以存在兼容性问题,部分系统级应用程序将无法正常运行。
负载均衡/高可用性集群
3、LVS(Linux Virtual Server)
这是一个由国人主持的项目。
它是一个负载均衡/高可用性集群,主要针对大业务量的网络应用(如新闻服务、网上银行、电子商务等)。
LVS
是建立在一个主控服务器(通常为双机)(director)及若干真实服务器(real-server)所组成的集群之上。real-server负责实
际提供服务,主控服务器根据指定的调度算法对real-server进行控制。而集群的结构对于用户来说是透明的,客户端只与单个的IP(集群系统的虚拟
IP)进行通信,也就是说从客户端的视角来看,这里只存在单个服务器。
N54537Real-server可以提供众多服务,如ftp,
http, dns, telnet, nntp, smtp
等。主控服务器负责对Real-Server进行控制。客户端在向LVS发出服务请求时,Director会通过特定的调度算法来指定由某个Real-
Server来应答请求,而客户端只与Load Balancer的IP(即虚拟IP,VIP)进行通信。
其他集群:
现在集群系统可谓五花八门,绝大部分的OS开发商,服务器开发商都提供了系统级的
集群产品,最典型的是各类双机系统,还有各类科研院校提供的集群系统。以及各类软件开发商提供的应用级别的集群系统,如数据库集
群,Application Server 集群,Web Server集群,邮件集群等等。
(四)负载均衡
1、概念
由于目前现有网络的各个核心部分随着业务量的提高,访问量和数据流量的快速增长,其处理能力和计算强度也相应地增大,使得单一的服务器设备根本无法承担。
在此情况下,如果扔掉现有设备去做大量的硬件升级,这样将造成现有资源的浪费,而且如果再面临下一次业务量的提升时,这又将导致再一次硬件升级的高额成本
投入,甚至性能再卓越的设备也不能满足当前业务量增长的需求。
针对此情况而衍生出来的一种廉价有效透明的方法以扩展现有网络设备和服务器的带宽、增加吞吐量、加强网络数据处理能力、提高网络的灵活性和可用性的技术就是负载均衡(Load Balance)。
2、特点和分类
负载均衡(Server Load Balance)一般用于提高服务器的整体处理能力,并提高可靠性,可用性,可维护性,最终目的是加快服务器的响应速度,从而提高用户的体验度。
负载均衡从结构上分为本地负载均衡(Local Server Load Balance)和地域负载均衡(Global Server Load
Balance)(全局负载均衡),一是指对本地的服务器群做负载均衡,另一是指对分别放置在不同的地理位置、有不同的网络及服务器群之间作负载均衡。
地域负载均衡有以下的特点:
(1)解决网络拥塞问题,服务就近提供,实现地理位置无关性
(2)对用户提供更好的访问质量
(3)提高服务器响应速度
(4)提高服务器及其他资源的利用效率
(5)避免了数据中心单点失效
3、负载均衡技术主要应用
(1)DNS负载均衡
最早的负载均衡技术是通过DNS来实现的,在DNS中为多个地址配置同一个名字,因而查询这个名字的客户机将得到其中一个地址,从而使得不同的客户访问不
同的服务器,达到负载均衡的目的。DNS负载均衡是一种简单而有效的方法,但是它不能区分服务器的差异,也不能反映服务器的当前运行状态。
(2)代理服务器负载均衡 使用代理服务器,可以将请求转发给内部的服务器,使用这种加速模式显然可以提升静态网页的访问速度。然而,也可以考虑这样一种技术,使用代理服务器将请求均匀转发给多台服务器,从而达到负载均衡的目的。
(3)地址转换网关负载均衡 支持负载均衡的地址转换网关,可以将一个外部IP地址映射为多个内部IP地址,对每次TCP连接请求动态使用其中一个内部地址,达到负载均衡的目的。
(4)协议内部支持负载均衡 除了这三种负载均衡方式之外,有的协议内部支持与负载均衡相关的功能,例如HTTP协议中的重定向能力等,HTTP运行于TCP连接的最高层。
(5)NAT
负载均衡 NAT(Network Address Translation
网络地址转换)简单地说就是将一个IP地址转换为另一个IP地址,一般用于未经注册的内部地址与合法的、已获注册的Internet
IP地址间进行转换。适用于解决Internet IP地址紧张、不想让网络外部知道内部网络结构等的场合下。
(6)反向代理负载均
衡
普通代理方式是代理内部网络用户访问internet上服务器的连接请求,客户端必须指定代理服务器,并将本来要直接发送到internet上服务器的连
接请求发送给代理服务器处理。反向代理(Reverse
Proxy)方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给
internet上请求连接的客户端,此时代理服务器对外就表现为一个服务器。反向代理负载均衡技术是把将来自internet上的连接请求以反向代理的
方式动态地转发给内部网络上的多台服务器进行处理,从而达到负载均衡的目的。
(7)混合型负载均衡
在有些大型网络,由于多个服务器群内硬件设备、各自的规模、提供的服务等的差异,我们可以考虑给每个服务器群采用最合适的负载均衡方式,然后又在这多个服
务器群间再一次负载均衡或群集起来以一个整体向外界提供服务(即把这多个服务器群当做一个新的服务器群),从而达到最佳的性能。我们将这种方式称之为混合
型负载均衡。此种方式有时也用于单台均衡设备的性能不能满足大量连接请求的情况下。
二、搭建集群和实现负载平衡
(一)前期准备
我的系统用的是windowsXP专业版,我要做的是,用一个apache和多个(这里以两个作为示例)tomcat,通过jk方式,构造一个集群。以下是要首先准备的东西:
1、jdk,我用的版本是jdk1.5.0_06,下载地址是http://192.18.108.216/ECom/EComTicketServlet/BEGIND597A309654D73D910E051D73D539D5F/-2147483648/2438196255/1/852050/851882/2438196255/2ts+/westCoastFSEND/jdk-1.5.0_13-oth-JPR/jdk-1.5.0_13-oth-JPR:3/jdk-1_5_0_13-windows-i586-p.exe
2、apache,我用的版本是2.2.4,下载地址是http://apache.justdn.org/httpd/binaries/win32/apache_2.2.4-win32-x86-openssl-0.9.8d.msi
3、tomcat,我用的版本是5.5的解压版本,这里要注意:不能用安装的版本,因为一台机器上装两个一样的tomcat,是会出错误的。下载地址是http://apache.mirror.phpchina.com/tomcat/tomcat-5/v5.5.25/bin/apache-tomcat-5.5.25.zip
4、jk,这个jk的版本,本来有两个的,但是版本2已经被废弃掉了,目前可用的jk版本是1.2.25。每个apache的版本,都会有一个特定的jk与之对应,所以这里要用的jk也必须是为apache-2.2.4开发的那个才行。它的下载地址是http://www.apache.org/dist/tomcat/tomcat-connectors/jk/binaries/win32/jk-1.2.25/mod_jk-apache-2.2.4.so
有了这四样东西,我们就可以开始做集群了。
(二)安装
1、相信需要看这篇文章的人,JDK的安装一定不会陌生,这里不在赘述。只是需要提醒一下:环境变量别忘记配置了。
2、安装apache也没有什么难度,就是在安装过程中要配置域名、网址和管理员邮箱之类的信息,这
个信息完全可以按照提示,然后修改下填入即可,之后想修改的话直接到配置文件中改就行了。除了这个地方,还要保证机器上的80端口没有被其他程序占用。至
于安装路径,完全取决于个人爱好。其他的默认就行了。安装成功后,系统右下角的托盘区会有个图标,我们可以通过这个启动apache,如果那个小红点变成
绿色,说明服务已经正常启动了(如果服务没有启动起来,说明安装过程中的配置有错误,建议卸载后重装)。如果按照默认,端口是80的话,那打开浏览器,输
入:http://localhost/ ,应该可以看到 " It works “的字样。这样就可以进入下一步了。
3、解压缩tomcat,记得要做两份。这里不妨将两个tomcat命名为:tomcat-
5.5.25_1和tomcat-5.5.25_2,其实这两个文件夹中的东西是完全一样的。但是我为了在同一台机器上做集群,那就要保证两个
tomcat运行起来不会在端口上起冲突。进入tomcat-5.5.25_1/conf目录,用文本编辑器打开并修改server.xml,将该
tomcat的默认8080端口改为8088(其实没必要改,我改这个是因为我机器上还有其他tomcat占用着8080端口)。然后进入tomcat-
5.5.25_2/conf目录,同样将8080修改掉,至于改成多少没多大关系,只要不占用其他程序的端口,应该不会出什么问题。这样,tomcat就
算安装好了。
4、jk这东西是一个连接模块,不用安装,直接将mod_jk-apache-2.2.4.so这个文件拷贝到apache安装目录下的modules文件夹下面就行了。
这样,安装完成,下面开始配置。
(三)配置
这个地方才是搭建集群的关键所在,我也会尽我的可能写的详细点。
1、配置tomcat
为防止冲突,进入第二个tomcat主目录,然后进入conf目录,打开server.xml修改配
置。主要是修改端口,我这里把所有的端口信息,都在原有基础上加1000,即原端口是8009,我改为9009。当然,你不必和我一样,只要保证不冲突就
OK!这些配置在apache的配置中可能会用到。
2、配置apache
(1)进入apache的主目录,然后进入conf文件夹,用文本编辑器打开httpd.conf,在该文件末尾加上如下几行:
### 加载 mod_jk 模块
LoadModule jk_module modules/mod_jk-apache-2.2.4.so
### 配置 mod_jk
JkWorkersFile conf/workers.properties #加载集群中的workers
JkMountFile conf/uriworkermap.properties #加载workers的请求处理分配文件
JkLogFile logs/mod_jk.log #指定jk的日志输出文件
JkLogLevel warn #指定日志级别
(2)不要改变目录,新建一个文件:workers.properties,该文件用来配置web容器的信息。该文件的内容如下:
# worker列表
worker.list=controller, status
#第一个server的配置,server名为s1
#ajp13 端口号,在tomcat下server.xml配置,默认8009
worker.s1.port=8009
#tomcat的主机地址,如不为本机,请填写ip地址
worker.s1.host=localhost
worker.s1.type=ajp13
#server的加权比重,值越高,分得的请求越多
worker.s1.lbfactor=1
#第二个server的配置,server名为s2
worker.s2.port=9009
worker.s2.host=localhost
worker.s2.type=ajp13
worker.s2.lbfactor=1
#server名为controller,用于负载均衡
worker.controller.type=lb
worker.retries=3 #重试次数
#指定分担请求的server列表,用逗号分隔
worker.controller.balanced_workers=s1,s2
#设置用于负载均衡的server的session可否共享 有不少文章说设置为1是可以的,但是我是设置为0才可以的
worker.controller.sticky_session=0
#worker.controller.sticky_session_force=1
worker.status.type=status
(3)不要改变目录,新建一个文件:uriworkermap.properties,文件内容如下:
/*=controller #所有请求都由controller这个server处理
/jkstatus=status #所有包含jkstatus请求的都由status这个server处理
!/*.gif=controller #所有以.gif结尾的请求都不由controller这个server处理,以下几个都是一样的意思
!/*.jpg=controller
!/*.png=controller
!/*.css=controller
!/*.js=controller
!/*.htm=controller
!/*.html=controller
这里的"!”类似于java中的"!”,是“非”的意思。
这样,apache一块就配置好了。
3、再修改tomcat配置:这里两个tomcat都要配置。
仍然是打开第一步中的那个server.xml文件,找到<Engine
name="Catalina"
defaultHost="localhost">这一行,在里面加上一句:jvmRoute="s1",即把该句改为:<Engine
name="Catalina" defaultHost="localhost"
jvmRoute="s1">。这里的s1就是第二步中配置的用于负载均衡的server的名称。如果该tomcat的端口是第二步中s1用的端
口,那这里就写s1,第二个tomcat就应该是s2了。
这样,配置就完成了。
(四)运行
进入两个tomcat的bin目录,执行两个tomcat的startup.bat启动这两个
tomcat,然后将apache重新启动后,运行起来看看效果吧。如果不出意外,两个tomcat的窗口应该是你一次我一次的打印日志信息了,而且此时
session也是共享了的。
到这里,集群搭建好了,负载均衡也实现了。
文章来源:
http://blog.163.com/ccbobo_cat/blog/static/32099462200932611544216
posted @
2009-04-26 11:54 C.B.K 阅读(193) |
评论 (0) |
编辑 收藏