摘要: 优化RandomAccessFile类后完整版代码
1.BufferedRandomAccessFile.java类
1 package kbps.io; 2 3 import java.io.RandomAccessFile; 4 imp... 阅读全文
通过扩展RandomAccessFile类使之具备Buffer改善I/O性能
JAVA的文件随机存取类(RandomAccessFile)的I/O效率较低。通过分析其中原因,提出解决方案。逐步展示如何创建具备缓存读写能力的文件随机存取类,并进行了优化。通过与其它文件访问类的性能对比,证明了其实用价值。
主体:
开发人员使用RandomAccessFile类时。其I/O性能较之其它常用开发语言的同类性能差距甚远,严重影响程序的运行效率。开发人员迫切需要提高效率,下面分析RandomAccessFile等文件类的源代码,找出其中的症结所在,并加以改进优化,创建一个"性/价比"俱佳的随机文件访问类BufferedRandomAccessFile。
在改进之前先做一个基本测试:逐字节COPY一个12兆的文件(这里牵涉到读和写)。
读 |
写 |
耗用时间(秒) |
RandomAccessFile |
RandomAccessFile |
95.848 |
BufferedInputStream + DataInputStream |
BufferedOutputStream + DataOutputStream |
2.935 |
我们可以看到两者差距约32倍,RandomAccessFile也太慢了。先看看两者关键部分的源代码,对比分析,找出原因。
1.1.[RandomAccessFile]
public class RandomAccessFile implements DataOutput, DataInput {
public final byte readByte() throws IOException {
int ch = this.read();
if (ch < 0)
throw new EOFException();
return (byte)(ch);
}
public native int read() throws IOException;
public final void writeByte(int v) throws IOException {
write(v);
}
public native void write(int b) throws IOException;
}
|
可见,RandomAccessFile每读/写一个字节就需对磁盘进行一次I/O操作。
1.2.[BufferedInputStream]
public class BufferedInputStream extends FilterInputStream {
private static int defaultBufferSize = 2048;
protected byte buf[]; // 建立读缓存区
public BufferedInputStream(InputStream in, int size) {
super(in);
if (size <= 0) {
throw new IllegalArgumentException("Buffer size <= 0");
}
buf = new byte[size];
}
public synchronized int read() throws IOException {
ensureOpen();
if (pos >= count) {
fill();
if (pos >= count)
return -1;
}
return buf[pos++] & 0xff; // 直接从BUF[]中读取
}
private void fill() throws IOException {
if (markpos < 0)
pos = 0; /* no mark: throw away the buffer */
else if (pos >= buf.length) /* no room left in buffer */
if (markpos > 0) { /* can throw away early part of the buffer */
int sz = pos - markpos;
System.arraycopy(buf, markpos, buf, 0, sz);
pos = sz;
markpos = 0;
} else if (buf.length >= marklimit) {
markpos = -1; /* buffer got too big, invalidate mark */
pos = 0; /* drop buffer contents */
} else { /* grow buffer */
int nsz = pos * 2;
if (nsz > marklimit)
nsz = marklimit;
byte nbuf[] = new byte[nsz];
System.arraycopy(buf, 0, nbuf, 0, pos);
buf = nbuf;
}
count = pos;
int n = in.read(buf, pos, buf.length - pos);
if (n > 0)
count = n + pos;
}
}
|
1.3.[BufferedOutputStream]
public class BufferedOutputStream extends FilterOutputStream {
protected byte buf[]; // 建立写缓存区
public BufferedOutputStream(OutputStream out, int size) {
super(out);
if (size <= 0) {
throw new IllegalArgumentException("Buffer size <= 0");
}
buf = new byte[size];
}
public synchronized void write(int b) throws IOException {
if (count >= buf.length) {
flushBuffer();
}
buf[count++] = (byte)b; // 直接从BUF[]中读取
}
private void flushBuffer() throws IOException {
if (count > 0) {
out.write(buf, 0, count);
count = 0;
}
}
}
|
可见,Buffered I/O putStream每读/写一个字节,若要操作的数据在BUF中,就直接对内存的buf[]进行读/写操作;否则从磁盘相应位置填充buf[],再直接对内存的buf[]进行读/写操作,绝大部分的读/写操作是对内存buf[]的操作。
1.3.小结
内存存取时间单位是纳秒级(10E-9),磁盘存取时间单位是毫秒级(10E-3),同样操作一次的开销,内存比磁盘快了百万倍。理论上可以预见,即使对内存操作上万次,花费的时间也远少对于磁盘一次I/O的开销。显然后者是通过增加位于内存的BUF存取,减少磁盘I/O的开销,提高存取效率的,当然这样也增加了BUF控制部分的开销。从实际应用来看,存取效率提高了32倍。
根据1.3得出的结论,现试着对RandomAccessFile类也加上缓冲读写机制。
随机访问类与顺序类不同,前者是通过实现DataInput/DataOutput接口创建的,而后者是扩展FilterInputStream/FilterOutputStream创建的,不能直接照搬。
2.1.开辟缓冲区BUF[默认:1024字节],用作读/写的共用缓冲区。
2.2.先实现读缓冲。
读缓冲逻辑的基本原理:
A 欲读文件POS位置的一个字节。
B 查BUF中是否存在?若有,直接从BUF中读取,并返回该字符BYTE。
C 若没有,则BUF重新定位到该POS所在的位置并把该位置附近的BUFSIZE的字节的文件内容填充BUFFER,返回B。
以下给出关键部分代码及其说明:
public class BufferedRandomAccessFile extends RandomAccessFile {
// byte read(long pos):读取当前文件POS位置所在的字节
// bufstartpos、bufendpos代表BUF映射在当前文件的首/尾偏移地址。
// curpos指当前类文件指针的偏移地址。
public byte read(long pos) throws IOException {
if (pos < this.bufstartpos || pos > this.bufendpos ) {
this.flushbuf();
this.seek(pos);
if ((pos < this.bufstartpos) || (pos > this.bufendpos))
throw new IOException();
}
this.curpos = pos;
return this.buf[(int)(pos - this.bufstartpos)];
}
// void flushbuf():bufdirty为真,把buf[]中尚未写入磁盘的数据,写入磁盘。
private void flushbuf() throws IOException {
if (this.bufdirty == true) {
if (super.getFilePointer() != this.bufstartpos) {
super.seek(this.bufstartpos);
}
super.write(this.buf, 0, this.bufusedsize);
this.bufdirty = false;
}
}
// void seek(long pos):移动文件指针到pos位置,并把buf[]映射填充至POS
所在的文件块。
public void seek(long pos) throws IOException {
if ((pos < this.bufstartpos) || (pos > this.bufendpos)) { // seek pos not in buf
this.flushbuf();
if ((pos >= 0) && (pos <= this.fileendpos) && (this.fileendpos != 0))
{ // seek pos in file (file length > 0)
this.bufstartpos = pos * bufbitlen / bufbitlen;
this.bufusedsize = this.fillbuf();
} else if (((pos == 0) && (this.fileendpos == 0))
|| (pos == this.fileendpos + 1))
{ // seek pos is append pos
this.bufstartpos = pos;
this.bufusedsize = 0;
}
this.bufendpos = this.bufstartpos + this.bufsize - 1;
}
this.curpos = pos;
}
// int fillbuf():根据bufstartpos,填充buf[]。
private int fillbuf() throws IOException {
super.seek(this.bufstartpos);
this.bufdirty = false;
return super.read(this.buf);
}
}
|
至此缓冲读基本实现,逐字节COPY一个12兆的文件(这里牵涉到读和写,用BufferedRandomAccessFile试一下读的速度):
读 |
写 |
耗用时间(秒) |
RandomAccessFile |
RandomAccessFile |
95.848 |
BufferedRandomAccessFile |
BufferedOutputStream + DataOutputStream |
2.813 |
BufferedInputStream + DataInputStream |
BufferedOutputStream + DataOutputStream |
2.935 |
可见速度显著提高,与BufferedInputStream+DataInputStream不相上下。
2.3.实现写缓冲。
写缓冲逻辑的基本原理:
A欲写文件POS位置的一个字节。
B 查BUF中是否有该映射?若有,直接向BUF中写入,并返回true。
C若没有,则BUF重新定位到该POS所在的位置,并把该位置附近的 BUFSIZE字节的文件内容填充BUFFER,返回B。
下面给出关键部分代码及其说明:
// boolean write(byte bw, long pos):向当前文件POS位置写入字节BW。
// 根据POS的不同及BUF的位置:存在修改、追加、BUF中、BUF外等情
况。在逻辑判断时,把最可能出现的情况,最先判断,这样可提高速度。
// fileendpos:指示当前文件的尾偏移地址,主要考虑到追加因素
public boolean write(byte bw, long pos) throws IOException {
if ((pos >= this.bufstartpos) && (pos <= this.bufendpos)) {
// write pos in buf
this.buf[(int)(pos - this.bufstartpos)] = bw;
this.bufdirty = true;
if (pos == this.fileendpos + 1) { // write pos is append pos
this.fileendpos++;
this.bufusedsize++;
}
} else { // write pos not in buf
this.seek(pos);
if ((pos >= 0) && (pos <= this.fileendpos) && (this.fileendpos != 0))
{ // write pos is modify file
this.buf[(int)(pos - this.bufstartpos)] = bw;
} else if (((pos == 0) && (this.fileendpos == 0))
|| (pos == this.fileendpos + 1)) { // write pos is append pos
this.buf[0] = bw;
this.fileendpos++;
this.bufusedsize = 1;
} else {
throw new IndexOutOfBoundsException();
}
this.bufdirty = true;
}
this.curpos = pos;
return true;
}
|
至此缓冲写基本实现,逐字节COPY一个12兆的文件,(这里牵涉到读和写,结合缓冲读,用BufferedRandomAccessFile试一下读/写的速度):
读 |
写 |
耗用时间(秒) |
RandomAccessFile |
RandomAccessFile |
95.848 |
BufferedInputStream + DataInputStream |
BufferedOutputStream + DataOutputStream |
2.935 |
BufferedRandomAccessFile |
BufferedOutputStream + DataOutputStream |
2.813 |
BufferedRandomAccessFile |
BufferedRandomAccessFile |
2.453 |
可见综合读/写速度已超越BufferedInput/OutputStream+DataInput/OutputStream。
优化BufferedRandomAccessFile。
优化原则:
- 调用频繁的语句最需要优化,且优化的效果最明显。
- 多重嵌套逻辑判断时,最可能出现的判断,应放在最外层。
- 减少不必要的NEW。
这里举一典型的例子:
public void seek(long pos) throws IOException {
...
this.bufstartpos = pos * bufbitlen / bufbitlen;
// bufbitlen指buf[]的位长,例:若bufsize=1024,则bufbitlen=10。
...
}
|
seek函数使用在各函数中,调用非常频繁,上面加重的这行语句根据pos和bufsize确定buf[]对应当前文件的映射位置,用"*"、"/"确定,显然不是一个好方法。
优化一:this.bufstartpos = (pos << bufbitlen) >> bufbitlen;
优化二:this.bufstartpos = pos & bufmask; // this.bufmask = ~((long)this.bufsize - 1);
两者效率都比原来好,但后者显然更好,因为前者需要两次移位运算、后者只需一次逻辑与运算(bufmask可以预先得出)。
至此优化基本实现,逐字节COPY一个12兆的文件,(这里牵涉到读和写,结合缓冲读,用优化后BufferedRandomAccessFile试一下读/写的速度):
读 |
写 |
耗用时间(秒) |
RandomAccessFile |
RandomAccessFile |
95.848 |
BufferedInputStream + DataInputStream |
BufferedOutputStream + DataOutputStream |
2.935 |
BufferedRandomAccessFile |
BufferedOutputStream + DataOutputStream |
2.813 |
BufferedRandomAccessFile |
BufferedRandomAccessFile |
2.453 |
BufferedRandomAccessFile优 |
BufferedRandomAccessFile优 |
2.197 |
可见优化尽管不明显,还是比未优化前快了一些,也许这种效果在老式机上会更明显。
以上比较的是顺序存取,即使是随机存取,在绝大多数情况下也不止一个BYTE,所以缓冲机制依然有效。而一般的顺序存取类要实现随机存取就不怎么容易了。
需要完善的地方
提供文件追加功能:
public boolean append(byte bw) throws IOException {
return this.write(bw, this.fileendpos + 1);
}
|
提供文件当前位置修改功能:
public boolean write(byte bw) throws IOException {
return this.write(bw, this.curpos);
}
|
返回文件长度(由于BUF读写的原因,与原来的RandomAccessFile类有所不同):
public long length() throws IOException {
return this.max(this.fileendpos + 1, this.initfilelen);
}
|
返回文件当前指针(由于是通过BUF读写的原因,与原来的RandomAccessFile类有所不同):
public long getFilePointer() throws IOException {
return this.curpos;
}
|
提供对当前位置的多个字节的缓冲写功能:
public void write(byte b[], int off, int len) throws IOException {
long writeendpos = this.curpos + len - 1;
if (writeendpos <= this.bufendpos) { // b[] in cur buf
System.arraycopy(b, off, this.buf, (int)(this.curpos - this.bufstartpos),
len);
this.bufdirty = true;
this.bufusedsize = (int)(writeendpos - this.bufstartpos + 1);
} else { // b[] not in cur buf
super.seek(this.curpos);
super.write(b, off, len);
}
if (writeendpos > this.fileendpos)
this.fileendpos = writeendpos;
this.seek(writeendpos+1);
}
public void write(byte b[]) throws IOException {
this.write(b, 0, b.length);
}
|
提供对当前位置的多个字节的缓冲读功能:
public int read(byte b[], int off, int len) throws IOException {
long readendpos = this.curpos + len - 1;
if (readendpos <= this.bufendpos && readendpos <= this.fileendpos ) {
// read in buf
System.arraycopy(this.buf, (int)(this.curpos - this.bufstartpos),
b, off, len);
} else { // read b[] size > buf[]
if (readendpos > this.fileendpos) { // read b[] part in file
len = (int)(this.length() - this.curpos + 1);
}
super.seek(this.curpos);
len = super.read(b, off, len);
readendpos = this.curpos + len - 1;
}
this.seek(readendpos + 1);
return len;
}
public int read(byte b[]) throws IOException {
return this.read(b, 0, b.length);
}
public void setLength(long newLength) throws IOException {
if (newLength > 0) {
this.fileendpos = newLength - 1;
} else {
this.fileendpos = 0;
}
super.setLength(newLength);
}
public void close() throws IOException {
this.flushbuf();
super.close();
}
|
至此完善工作基本完成,试一下新增的多字节读/写功能,通过同时读/写1024个字节,来COPY一个12兆的文件,(这里牵涉到读和写,用完善后BufferedRandomAccessFile试一下读/写的速度):
读 |
写 |
耗用时间(秒) |
RandomAccessFile |
RandomAccessFile |
95.848 |
BufferedInputStream + DataInputStream |
BufferedOutputStream + DataOutputStream |
2.935 |
BufferedRandomAccessFile |
BufferedOutputStream + DataOutputStream |
2.813 |
BufferedRandomAccessFile |
BufferedRandomAccessFile |
2.453 |
BufferedRandomAccessFile优 |
BufferedRandomAccessFile优 |
2.197 |
BufferedRandomAccessFile完 |
BufferedRandomAccessFile完 |
0.401 |
与JDK1.4类MappedByteBuffer+RandomAccessFile的对比?
JDK1.4提供了NIO类 ,其中MappedByteBuffer类用于映射缓冲,也可以映射随机文件访问,可见JAVA设计者也看到了RandomAccessFile的问题,并加以改进。怎么通过MappedByteBuffer+RandomAccessFile拷贝文件呢?下面就是测试程序的主要部分:
RandomAccessFile rafi = new RandomAccessFile(SrcFile, "r");
RandomAccessFile rafo = new RandomAccessFile(DesFile, "rw");
FileChannel fci = rafi.getChannel();
FileChannel fco = rafo.getChannel();
long size = fci.size();
MappedByteBuffer mbbi = fci.map(FileChannel.MapMode.READ_ONLY, 0, size);
MappedByteBuffer mbbo = fco.map(FileChannel.MapMode.READ_WRITE, 0, size);
long start = System.currentTimeMillis();
for (int i = 0; i < size; i++) {
byte b = mbbi.get(i);
mbbo.put(i, b);
}
fcin.close();
fcout.close();
rafi.close();
rafo.close();
System.out.println("Spend: "+(double)(System.currentTimeMillis()-start) / 1000 + "s");
|
试一下JDK1.4的映射缓冲读/写功能,逐字节COPY一个12兆的文件,(这里牵涉到读和写):
读 |
写 |
耗用时间(秒) |
RandomAccessFile |
RandomAccessFile |
95.848 |
BufferedInputStream + DataInputStream |
BufferedOutputStream + DataOutputStream |
2.935 |
BufferedRandomAccessFile |
BufferedOutputStream + DataOutputStream |
2.813 |
BufferedRandomAccessFile |
BufferedRandomAccessFile |
2.453 |
BufferedRandomAccessFile优 |
BufferedRandomAccessFile优 |
2.197 |
BufferedRandomAccessFile完 |
BufferedRandomAccessFile完 |
0.401 |
MappedByteBuffer+ RandomAccessFile |
MappedByteBuffer+ RandomAccessFile |
1.209 |
确实不错,如果以后采用1.4版本开发软件时,需要对文件进行随机访问,建议采用MappedByteBuffer+RandomAccessFile的方式。但鉴于目前采用JDK1.3及以前的版本开发的程序占绝大多数的实际情况,如果您开发的JAVA程序使用了RandomAccessFile类来随机访问文件,并因其性能不佳,而担心遭用户诟病,请试用本文所提供的BufferedRandomAccessFile类,不必推翻重写,只需IMPORT 本类,把所有的RandomAccessFile改为BufferedRandomAccessFile,您的程序的性能将得到极大的提升,您所要做的就这么简单。
未来的考虑
读者可在此基础上建立多页缓存及缓存淘汰机制,以应付对随机访问强度大的应用。
(完整代码见下篇)
我爸和我后母结婚的时候,我读初二。我后母比我爸小了整整十五岁……最初是我爸的下属,死不要脸地追我爸,我爸的确是比较有魅力的那种男人,但是她也是特别地不要脸,知道别人是有妇之夫还要追……后来我爸妈离婚,她就跟我爸结了婚……一句话,她就是一个不折不扣的二奶,不过比二奶还要无耻一点,是晋级了的二奶……自从他们结了婚,我的生活里除了上学,主要的事情就是对付我后妈……她让我妈不好过,这些年我也没让她太爽……我的脑子有一半的力气都花在恶作剧上了…… 恶作剧一 偷偷用洗碗的铁丝球划她的丝袜,而且还是专门挑收在衣橱里丝袜抽屉的划,因为那些丝袜都是贵的几百块一双的那种。每次就划开两三条丝,刚开始,她都不知道是我划坏的。 恶作剧二 用针和剪刀把她的衣服拆线。特别是上衣的腋部和长裤的裆部。而且都是拆里面的那层隐线,穿的时候根本看不出来,但是一穿,一走动,线马上就开了。哈哈,看见那个无耻的婊 子穿着露内裤的长裤去跟客户谈判,我心里爽的要死!我还在她内衣上动过手脚,让她一整天背后都垂着一条bra带在公司里跑来跑去!我不只一次看见她因为衣服脱线而气急败坏,还曾经拿着衣服去商店投诉过。 后来有一次,她买了一件贵的大衣,将近八千多,我在屋里听到她和同事电话说起这件衣服,就留心想:这件衣服我一定要把它弄坏弄到补都不能补。我把那件纯白色毛料的大衣的背部放在煤气上烧……烧出了一个大洞。当时我就知道这么一来她肯定就知道以前的事情也是我干的了,但是还是义无反顾地做了,做的时候心理很有一种悲壮的感觉,觉得自己在给我妈出气。那种视死如归的感觉到现在都还记得。 这件事把我后母几乎气得抓狂,告诉我爸,我爸把我痛揍了一顿……那天晚上我整晚上都没睡觉,在卧室里把门反锁着,趴在窗户前面大声哭……还用书卷了个喇叭对着哭……哭声把半个小区的人都惊动了……后来我每次惹了我后母,她骂我一句,我一声不坑就地跑到窗户边哭……后来我和小区的几个同龄女孩子混熟了,经常在花坛边跳皮筋,大家都知道了我有个后妈,而且这个后妈还是“当狐狸精”抢别人的老公来的,小女孩子们回家都跟父母说,小区的人都很同情我……特别是那些老太太,有时候我放学回来看见了,在门口买菜的中年妇女看见了就要议论一句“这孩子学习还特别好呢,可惜了……”当然,我后妈的名声因此在小区变得特别臭,连开电梯的阿姨都鄙视她…… 恶作剧三 在她的香水里偷偷加盐或者味精或者雪碧其它什么东西……反正加了看不大出来的那种乱七八糟的东西……我有次上化学实验还让男生偷偷给我弄了点高锰酸钾,就是做氧气那个……后来也没敢放,因为胆子还小,怕放了中毒什么的我就惨了……我还想过往她香水里倒点尿之类的,后来自己觉得怪恶心,就也没有付诸实施…… 恶作剧四 自从跟了我后妈,我的衣服和鞋子都变得特别容易破……尤其是球鞋和袜子,经常是前面一个大破洞……我们上机房都是要换鞋的,每次我换鞋的时候就露出破破烂烂的袜子……我的同学缘很好,每次我同学他们就非常气愤,诅咒“那个死女人”(好朋友们都这么称呼我后妈)不得好死……我爸看了很气,就经常拿钱给我去买鞋买衣服……然后他当然也不知道物品的价钱,每次都胡乱给了不少钱……我攒上两三次多半就能攒个六七百,然后去商场买东西孝敬我妈或者我奶奶……我奶奶问我哪里来的钱,我就说我爸给我买鞋子的……我奶奶看看我的穿戴,就觉得我特别孝顺懂事,然后就大骂一通我后妈是狐狸精,然后会带着我去商店给我买衣服买鞋……反正我是赚回来了…… 我后妈和我爸后来就经常吵架,因为我奶奶很厌恶她,而且如果亲家母遇到了,我奶奶对她妈也很不客气……当然这里面很大的功劳都归功于我在中间用各种方式煽风点火……让我奶奶总觉得我在家特别受虐待……不过我后母对我本来就不好…… 恶作剧五 中学的时候住家里,我经常把家里的设施故意弄坏……比如往下水道倒剩菜,用过的卫生巾直接扔到抽水马桶里,开了冰箱就不关(当然要赶在父母下班前关上),夏天里把空调开到二十四五度,然后裹着棉被睡觉(为了把空调往死里用,用坏最好),吃饭的时候,我后妈炒完菜,我经常失手打翻……我后妈骂我,我就说:“我又不知道……我又不是故意的……你干吗这么挑剔……”我后妈如果说:“你有这么笨吗?一个盘子都拿不住吗?”我就说:“我就是笨啊,女儿都遗传爸爸的,你问我爸去啊?”她如果说:“我上次不是说了吗?剩菜不能倒在下水道里!你就是故意的。”我就说:“我不记得了啊!顺手就倒了!随便你啊,你看我不顺眼,当然觉得我是故意的罗!”每次都把她噎得半死。但是有客人在家,我就会特别老实……我后妈让做什么就做什么,而且经常用眼睛瞟她,装得很怕她的样子……我现在想起来觉得我真是天生当演员的料……那么小的年纪就知道做虚弄假……所以我们家亲戚朋友都觉得我很乖……我估计如果我后妈跟人说我在家里怎么怎么使坏,他们肯定会想“怪不得人家说后妈的孩子可怜,怪不得她那么怕你呢……” 恶作剧六 我初三的时候参加市里的新概念作文,得了一等奖,里面写的是我妈,里面就写了家庭变故,就是第三者插足,后来父母离婚,那个第三者嫁给了我爸等等,那作文写得很煽情……我在班上念,我们班同学听得热泪盈眶的说,要是放在现在,也算是篇悲情小说了……期中考试我考了年级第一,家长会上先是前三名家长介绍经验,我爸和别的家长满面春风地介绍了一通……然后是学生的成果展和节目表演……我的节目就是念我那篇获奖作文……我在上面念,下面众目睽睽地听,念到后面,家长们都在下面窃窃私语,我爸和我后妈在下面听得脸一阵红一阵白……当时很痛快,代价就是我回家又被我爸痛揍一顿…… 恶作剧七 我现在想起来,那时候很有点肆无忌惮的意思,我爸虽然有时候痛揍我,不过因为他就我一个女儿(我后妈怕影响体形,不肯生孩子),所以心里还是很疼我的说,而且我学习一向很好,年年被评市三好,初中和高中的时候还被评过省三好……后来又保送上了一个好大学……所以总的来说还是比较纵容我的……我的要求基本是有求必应……我小时候很尊敬我爸,但是都是因为他和我妈的事情,我的心里一直有疙瘩……有时候我是很想原谅他,但是人的心理是这样的,理智有的时候真的很难控制感情……我妈后来一直没有结婚,一个人住着一套旧房子,每次我想起我妈,我对我爸就根本爱不起来。 -我上大学的时候,花钱很厉害……因为我觉得不花白不花,我爸的钱我不花那个女人也要花……我毕业以后才知道隔壁班的同学称我每次都是“**(专业)班的那个头号富婆”……那时候我每个月生活费经常七八千都打不住……还不算作平时过生日出去旅游之类的花销……我放假回家,一家人出去吃饭,我后妈讽刺我说:“你读书怎么每个月花那么多钱?都快赶上我工资了”我就顶嘴说:“我花钱关你屁事,你嫁我爸不就是看上他的钱“,一点都不顾忌。我后妈骂我没家教,我就说我再没家教也不去泡别人的老公。把边上的服务小姐听得一愣一愣的,特别解恨。我在家给我妈打电话,每次都故意当着他们的面说将来我结了婚出国什么什么的肯定把她带着,以后要让我妈过好日子,以后过得比谁都舒服。反正是什么话刺激他们就专挑什么话。 我在家的时候,就什么都对着她干……比如我自己有自己的化妆品……但是每次都狠用她的……尤其是香水精华油之类……后来我每次回家,她就得把自己得化妆品收回卧室……每次出门还得把卧室锁着……晚上她睡觉前要跑步,我看看时间差不多了就赶快上跑步机,边看电视边跑……结果每年放假回家都要瘦一圈……因为我存心霸占跑步机……她总不能把我硬赶下来……后来我一回家,她就只好去健身房办卡,虽然家里有跑步机这。我bf是学医的,我还想过不少回弄点激素什么的涂在她的维生素丸或者花粉里……让她怎么保持都会象猪一样胖起来。不过我还算仁慈了,没有付诸实施……我后母当然每次都跟我骂骂咧咧,不过我就当没听见好了……反正我又不能掉块肉,可是自己解气,我算是狠赚的,我连我爸的巴掌都不怕,怕她个鸟。 刚上大学的时候,我忘记从哪里看到的一个狠办法,如果把我爸和后妈床头柜里的套套戳几个洞……但是我找到他们用的套套才发现套套是有包装袋的,如果我拆开了戳洞他们肯定会发现……结果不了了之……那个想法有点太弱智了……不知道哪个混蛋想出来的……无耻的二奶,不要脸的第三者,我恨她!
历史上最愚蠢的八大事件
1.1971年,一位亚利桑那人开枪打伤了自己。这倒没有什么可大惊小怪的,这种事情时有发生。可是为了提高呼救声的分贝,这位受伤的人又开了一枪,打中了另外一条腿。 2.一位在竞选活动的民意调查中落后的日本政客,为了获得同情的支持选票,制造出被人暗杀的假象。为了使暗杀看上去确有其事,这位政客用刀在自己腿上砍了一刀。没想到砍断了动脉,血流如注。在发表最后的竞选演说之前,他就一命呜呼。 3.17世纪的西班牙国王菲利普三世因发烧而去世,他的高烧是由于长时间坐在炉火旁而引起的。 既然他知道温度高,可为什么不从炉火那里移开呢?原因是:那不是他作为国王的工作。宫廷里负责照看炉火的佣人没有上班这名佣人的工作就是把国王的座椅往后拉。 4.一个法国人1998年尝试一次复杂的自杀。他站在一个高高的悬崖上,在脖子上套上一个索套,把绳索固定在一块巨大的岩石上。然后他喝下了毒药,并开始自杀悬崖上跳下去的时候,他又朝着自己的脑袋开了一枪。 结果是:子弹没有打中目标,反而打穿了绳索,因此他掉到了海里而没能吊死。冰冷的海水扑灭了他衣服上的火焰,而且这种冲击力使他把毒药呕吐出来。 一位渔民把他从水里拖了起来,送到医院,结果他由于体温过低而死亡。 5.1932年洛杉矶奥运会。当法国的朱利?内尔打破了铁饼的奥运会纪录时,他那获胜的一掷被判无效并非他违反了任何比赛规则,而是因为所有本应该注视着铁饼比赛的裁判员都转过头去观看撑杆跳高了。 6.在投篮秒表出现之前,伊利诺伊州有过这样一场比赛:比赛开始不久,乔治城队罚球得了一分,接着他们就把球藏起来了,霍马队的队员毫无办法,只好在球场上席地而坐,而裁判则在看报纸。当比赛时间结束时,乔治城队开始庆祝他们1:0的胜利。 7.一位乌克兰商人给他的50名员工每人买了一个传呼机作为礼物。在他返回的路上,这50个传呼机同时叫了起来,他由于受惊过度以至于把车撞到电线杆上。 检查完伤势之后,他开始查看传呼机上的信息。只见这50个传呼机上出现了同一句话:“感谢购买本机!” 8.1968年,底特律的一个窃贼带着他的爱犬入室行窃。当警察发现时,窃贼仓皇逃走,却把爱犬留在后面。警察非常容易地就抓住了窃贼,因为他们只是对狗说了句:“回家,宝贝!”
listner.log如果达到2G,数据库将无法建立连接。 解决办法有两个: 1) 用script定期切换日志 2) 设置log_status 现给出第二种方法: 1) 以oracle身份进入linux 2) lsnrctl 3) set log_status off 4) save_config 完成,listner.log不会再涨了。
以oracle 用户登陆,允许sqlplus "sys/oracle as sysdba"
1.shutdown abort
2.startup nomount pfile=/home/oracle/admin/shlbs/pfile/initshlbs.ora
3.如果startup nomount正常则 重做控制文件 CREATE CONTROLFILE REUSE DATABASE "SHLBS" NORESETLOGS ARCHIVELOG MAXLOGFILES 16 MAXLOGMEMBERS 3 MAXDATAFILES 100 MAXINSTANCES 8 MAXLOGHISTORY 454 LOGFILE GROUP 1 '/home/oracle/oradata/shlbs/redo01.log' SIZE 100M,GROUP 2 '/home/oracle/oradata/shlbs/redo02.log' SIZE 100M,GROUP 3 '/home/oracle/oradata/shlbs/redo03.log' SIZE 100M DATAFILE '/home/oracle/oradata/shlbs/CITYMGR.dbf','/home/oracle/oradata/shlbs/cwmlite01.dbf','/home/oracle/oradata/shlbs/drsys01.dbf','/home/oracle/oradata/shlbs/example01.dbf','/home/oracle/oradata/shlbs/indx01.dbf','/home/oracle/oradata/shlbs/LBS.dbf','/home/oracle/oradata/shlbs/odm01.dbf','/home/oracle/oradata/shlbs/system01.dbf','/home/oracle/oradata/shlbs/tools01.dbf','/home/oracle/oradata/shlbs/undotbs01.dbf','/home/oracle/oradata/shlbs/users01.dbf','/home/oracle/oradata/shlbs/xdb01.dbf' CHARACTER SET ZHS16GBK
4.如果需要,重做口令文件 orapwd file=口令文件路径和文件名 password=test entries=2
5.如果重做控制文件成功,则恢复数据库 recover database;
以上操作具体参数可能和具体数据相关,请修改。
linux联盟原创www.xxlinux.com www.linuxunion.org转贴请标明出处 作者上上智
看了这么久的blog,我自写一点配置哈 现在有很多想学习linux的人, 就是因为不能配置上网,所以不想学习现在我从adsl配置到nat全过程如下: 1)安装rp-pppoe-3.5-2包 在安装系统时,对新用户一般选择全部安装的,那就安装了,以后rpm, 或者tarball了,这很方便,对初学者: eg: rpm -ivh rp-pppoe-3.5-2.rpm tarball 安装: tar zxvf rp-pppoe-3.5-2.tar.gz cd rp-pppoe-3.5-2 ./configure make make install 2)rp-pppoe-3.5-2配置 步骤: a) adsl-setup 出现: Welcome to the ADSL client setup. First, I will run some checks on your system to make sure the PPPoE client is installed properly... The following DSL config was found on your system: Device: Name: ppp0 Please enter the device if you want to configure the present DSL config (default ppp0) or enter 'n' if you want to create a new one: //这是我已经安装过了,主要是写文档:选择默认按回车 LOGIN NAME Enter your Login Name (default lanlgn409ldj@zgcnc): //这是我已经安装过了,:没有安装是输入adsl用户名 INTERFACE Enter the Ethernet interface connected to the ADSL modem For Solaris, this is likely to be something like /dev/hme0. For Linux, it will be ethX, where 'X' is a number. (default eth0): //选择默认按回车 Do you want the link to come up on demand, or stay up continuously? If you want it to come up on demand, enter the idle time in seconds after which the link should be dropped. If you want the link to stay up permanently, enter 'no' (two letters, lower-case.) NOTE: Demand-activated links do not interact well with dynamic IP addresses. You may have some problems with demand-activated links. Enter the demand value (default no): //选择默认按回车 DNS Please enter the IP address of your ISP's primary DNS server. If your ISP claims that 'the server will provide dynamic DNS addresses', enter 'server' (all lower-case) here. If you just press enter, I will assume you know what you are doing and not modify your DNS setup. Enter the DNS information here: // 输入server自动得到dns,server的ip PASSWORD Please enter your Password:
USERCTRL Please enter 'yes' (two letters, lower-case.) if you want to allow normal user to start or stop DSL connection (default yes): //选择默认按回车问你是否连接 Please choose the firewall rules to use. Note that these rules are very basic. You are strongly encouraged to use a more sophisticated firewall setup; however, these will provide basic security. If you are running any servers on your machine, you must choose 'NONE' and set up firewalling yourself. Otherwise, the firewall rules will deny access to all standard servers like Web, e-mail, ftp, etc. If you are using SSH, the rules will block outgoing SSH connections which allocate a privileged source port. The firewall choices are: 0 - NONE: This script will not set any firewall rules. You are responsible for ensuring the security of your machine. You are STRONGLY recommended to use some kind of firewall rules. 1 - STANDALONE: Appropriate for a basic stand-alone web-surfing workstation 2 - MASQUERADE: Appropriate for a machine acting as an Internet gateway for a LAN Choose a type of firewall (0-2): //是否设置firwall Do you want to start this connection at boot time? Please enter no or yes (default no): //启动时是否连接 Do you want to start this connection at boot time? Please enter no or yes (default no): ** Summary of what you entered ** Ethernet Interface: eth0 User name: lanlgn409ldj@zgcnc Activate-on-demand: No DNS: Do not adjust Firewalling: NONE User Control: yes Accept these settings and adjust configuration files (y/n)? //是否写入配置文件里 选择 y 3)假如你是用别人的mac连接 1 redhat9.0改mac: ifconfig eth0 down ifconfig eth0 hw ether 5254ab323d51 ifconfig eth0 up ifup ppp0 2 fedora 4.0改mac: ifdown eth0 ifconfig eth0 hw ether 5254ab323d51 ifup eth0 ifup ppp0 & adsl-start 4)测试一下 ping www.baidu.com 5)做nat echo "1" > /proc/sys/net/ipv4/ip_forward //这很重要,路由转发 modprobe ip_tables modprobe ip_nat_ftp modprobe ip_nat_irc modprobe ip_conntrack modprobe ip_conntrack_ftp modprobe ip_conntrack_irc /sbin/iptables -F /sbin/iptables -X /sbin/iptables -Z /sbin/iptables -F -t nat /sbin/iptables -X -t nat /sbin/iptables -Z -t nat /sbin/iptables -P INPUT ACCEPT /sbin/iptables -P OUTPUT ACCEPT /sbin/iptables -P FORWARD ACCEPT /sbin/iptables -t nat -P PREROUTING ACCEPT /sbin/iptables -t nat -P POSTROUTING ACCEPT /sbin/iptables -t nat -P OUTPUT ACCEPT /sbin/iptables -t nat -A POSTROUTING -o ppp0 -s 192.168.0.0/24 -j MASQUERADE//不是adsl也可以把ppp0改成eth0 , 1一般网卡nat: [root@test root]# vi /etc/sysconfig/network-scripts/ifcfg-eth0 DEVICE=eth0 BOOTPROTO=dhcp BROADCAST=192.168.0.255 IPADDR=192.168.0.1 NETMASK=255.255.255.0 NETWORK=192.168.0.0 ONBOOT=yes [root@test root]# vi /etc/sysconfig/network-scripts/ifcfg-eth0:0 DEVICE=eth0:0 BOOTPROTO=static BROADCAST=192.168..255 IPADDR=192.168.1.2 NETMASK=255.255.255.0 NETWORK=192.168..0 ONBOOT=yes 2 两块网卡nat: 只是那個 eth0:0 改成了 eth1 而已啦,其它都是一样的设置 6)dns 设置 在里面/etc/resolv.conf 把你的ip写入里面去 nameserver 192.168.0.1 然后重启要不然,客户机不能上网
问题引发: 服务器每天产生大量的系统日志,查询日志,目前日志这块没有人专门拿出来做分析,处理这些日志.随着时间以及服务器访问量的与日俱增,不小心就会出现硬盘被日志文件占满的现象.如果删除这些日志,以后日志分析也许要用到.不删现有服务会受到影响.以后可能会专门有一台服务器来处理这些日志,分析日志,估算出性能瓶颈,以及得出相应的有价值的商业信息.所以只能临时处理一下. 看了一下linux的压缩格式好多种,忽然一看有些晕,发一篇关于linux压缩文件的详细文章,摘自:Unix爱好者家园unix-cd.com ,以下是原文 对于刚刚接触 Linux 的人来说,一定会给 Linux 下一大堆各式各样的文件名给搞晕。别个不说,单单就压缩文件为例,我们知道在 Windows 下最常见的压缩文件就只有两种,一是 .zip,另一个是 .rar。可是 Linux 就不同了,它有.gz、.tar.gz、tgz、bz2、.Z、.tar 等众多的压缩文件名,此外 windows 下的 .zip 和 .rar 也可以在 Linux 下使用,不过在 Linux 使用 .zip 和 .rar 的人就太少了。 在具体总结各类压缩文件之前呢,首先要弄清两个概念:打包和压缩。打包是指将一大堆文件或目录什么的变成一个总的文件,压缩则是将一个大的文件通过一些压缩算法变成一个小文件。为什么要区分这两个概念呢?其实这源于 Linux 中的很多压缩程序只能针对一个文件进行压缩,这样当你想要压缩一大堆文件时,你就得先借助另它的工具将这一大堆文件先打成一个包,然后再就原来的压缩程序进行压缩。 Linux下最常用的打包程序就是 tar 了,使用 tar 程序打出来的包我们常称为 tar 包,tar 包文件的命令通常都是以 .tar 结尾的。生成 tar 包后,就可以用其它的程序来进行压缩了,所以我们先了解一下 tar 命令的基本用法: tar 命令的选项有很多(用man tar可以查看到),但我们通常需要的就是那么几个: # tar -cf all.tar *.jpg 这条命令是将所有 .jpg 的文件打成一个名为 all.tar 的包。-c 是表示产生新的包,-f 指定包的文件名。 # tar -rf all.tar *.gif 这条命令是将所有.gif的文件增加到 all.tar 的包里面去。-r 是表示增加文件的意思。 # tar -uf all.tar logo.gif 这条命令是更新原来 tar 包 all.tar 中 logo.gif 文件,-u是表示更新文件的意思。 # tar -tf all.tar 这条命令是列出 all.tar 包中所有文件,-t 是列出文件的意思 # tar -xf all.tar 这条命令是解出 all.tar 包中所有文件,-t 是解开的意思 以上就是 tar 的最基本的用法。为了方便用户在打包解包的同时可以压缩或解压文件,tar 提供了一种特殊的功能。这就是 tar 可以在打包或解包的同时调用其它的压缩程序,比如调用 gzip、bzip2 等。 (一)、 tar 调用 gzip gzip 是 GNU 组织开发的一个压缩程序,.gz 结尾的文件就是 gzip 压缩的结果。与 gzip 相对的解压程序是 gunzip。tar 中使用 -z 这个参数来调用 gzip。下面来举例说明一下: # tar -czf all.tar.gz *.jpg 这条命令是将所有 .jpg 的文件打成一个 tar 包,并且将其用 gzip 压缩,生成一个 gzip 压缩过的包,包名为 all.tar.gz。 # tar -xzf all.tar.gz 这条命令是将上面产生的包解开。 (二)、 tar 调用 bzip2 bzip2 是一个压缩能力更强的压缩程序,.bz2 结尾的文件就是 bzip2 压缩的结果。与 bzip2 相对的解压程序是 bunzip2。tar 中使用-j这个参数来调用 gzip。下面来举例说明一下: # tar -cjf all.tar.bz2 *.jpg 这条命令是将所有 .jpg 的文件打成一个 tar 包,并且将其用 bzip2 压缩,生成一个 bzip2 压缩过的包,包名为 all.tar.bz2。 # tar -xjf all.tar.bz2 这条命令是将上面产生的包解开。 (三)、 tar 调用 compress compress 也是一个压缩程序,但是好象使用 compress 的人不如 gzip 和 bzip2 的人多。.Z 结尾的文件就是 bzip2 压缩的结果。与 compres s相对的解压程序是 uncompress。tar 中使用 -Z 这个参数来调用 gzip。下面来举例说明一下: # tar -cZf all.tar.Z *.jpg 这条命令是将所有 .jpg 的文件打成一个 tar 包,并且将其用 compress 压缩,生成一个 uncompress 压缩过的包,包名为 all.tar.Z # tar -xZf all.tar.Z 这条命令是将上面产生的包解开 有了上面的知识,你应该可以解开多种压缩文件了,下面对于 tar 系列的压缩文件作一个小结: (一)、对于 .tar 结尾的文件 tar -xf all.tar (二)、对于 .gz 结尾的文件 gzip -d all.gz gunzip all.gz (三)、对于 .tgz 或 .tar.gz 结尾的文件 tar -xzf all.tar.gz tar -xzf all.tgz (四)、对于 .bz2 结尾的文件 bzip2 -d all.bz2 bunzip2 all.bz2 (五)、对于 tar.bz2 结尾的文件 tar -xjf all.tar.bz2 (六)、对于 .Z 结尾的文件 uncompress all.Z (七)、对于.tar.Z结尾的文件 tar -xZf all.tar.z 另外对于 Window 下的常见压缩文件 .zip 和 .rar,Linux 也有相应的方法来解压它们: (1)对于 .zip linux 下提供了 zip 和 unzip 程序,zip 是压缩程序,unzip 是解压程序。它们的参数选项很多,这里只做简单介绍,依旧举例说明一下其用法: # zip all.zip *.jpg 这条命令是将所有 .jpg 的文件压缩成一个 zip 包 # unzip all.zip 这条命令是将 all.zip 中的所有文件解压出来 (2)对于 .rar 要在 linux 下处理 .rar 文件,需要安装 RAR for Linux,可以从网上下载,但要记住,RAR for Linux 不是免费的;可从 http://www.rarsoft.com/download.htm 下载 RAR for Linux 3.2.0,然后安装: # tar -xzpvf rarlinux-3.2.0.tar.gz # cd rar # make 这样就安装好了,安装后就有了 rar 和 unrar 这两个程序,rar 是压缩程序,unrar 是解压程序。它们的参数选项很多,这里只做简单介绍,依旧举例说明一下其用法: # rar a all *.jpg 这条命令是将所有 .jpg 的文件压缩成一个 rar 包,名为 all.rar,该程序会将 .rar 扩展名将自动附加到包名后。 # unrar e all.rar 这条命令是将 all.rar 中的所有文件解压出来 到此为至,我们已经介绍过 linux 下的 tar、gzip、gunzip、bzip2、bunzip2、compress、uncompress、zip、unzip、rar、unrar 等程式,你应该已经能够使用它们对 .tar、.gz、.tar.gz、.tgz、.bz2、.tar.bz2、.Z、.tar.Z、.zip、.rar 这 10 种压缩文件进行解压了,以后应该不需要为下载了一个软件而不知道如何在 Linux 下解开而烦恼了。而且以上方法对于 Unix 也基本有效。 本文介绍了 linux 下的压缩程式 tar、gzip、gunzip、bzip2、bunzip2、compress、uncompress、zip、unzip、rar、unrar 等程式,以及如何使用它们对 .tar、.gz、.tar.gz、.tgz、.bz2、.tar.bz2、.Z、.tar.Z、.zip、.rar 这 10 种压缩文件进行操作。
3.2 VSFTP 安全与效能兼备的ftp 服务器 3.2.1 VSFTP 概述 FTP,file transfer protocol,这是档案传输的通讯协议,也是一般最常用来传送档案的方式。读者在使用RedHat9 的时候,可能会感受到ftp server 有一些改变:第一,就是ftp server 只剩下vsftp,原有的wuftp 等都没放入 第二,就是vsftp 从XINETD 中独立出来,并将设定档从/etc/vsftpd.conf 之中移到/etc/vsftpd/vsftpd.conf。 为什么做这样的改变?可以想见的是vsftp 已有独立运作的能力,不需要XINETD 来做更进一步的管控,并且类似sendmail、httpd、ssh、samba 等,将设定文件的放入/etc 下独立的目录。 FTP 分为两类,一种为PORT FTP,也就是一般的FTP 另一类是PASVFTP,分述如下: PORT FTP 这是一般形式的FTP,首先会建立控制频道,默认值是port 21,也就是跟port 21 建立联机,并透过此联机下达指令。第二,由FTP server 端会建立数据传输频道,默认值为20,也就是跟port 20 建立联机,并透过port 20 作数据的传输。 PASV FTP 跟PORT FTP 类似,首先会建立控制频道,默认值是port 21,也就是跟port 21 建立联机,并透过此联机下达指令。第二,会由client 端做出数据传输的请求,包括数据传输port 的数字。 这两者的差异为何?PORT FTP 当中的数据传输port 是由FTP server 指定,而PASV FTP 的数据传输port 是由FTP client 决定。通常我们使用PASV FTP,是在有防火墙的环境之下,透过client 与server 的沟通,决定数据传输的port。 3.2.2 范例 3.2.1. 直接启动VSFTP 服务 这个范例是套用RedHat 的预设范例,直接启动vsftp。 [root@relay vsftpd]# /sbin/service vsftpd start Starting vsftpd for vsftpd: OK ] 3.2.2. 更换port 提供服务:将预设的port 21 更换为2121 为了安全,或是以port 来区隔不同的ftp 服务,我们可能会将ftp port 改为21 之外的port,那么,可参考以下步骤。 Step1. 修改/etc/vsftpd/vsftpd.conf 新增底下一行 listen_port=2121 Step2. 重新启动vsftpd [root@home vsftpd]# /sbin/service vsftpd restart Shutting down vsftpd: OK ] Starting vsftpd for vsftpd: OK ] 3.2.3. 特定使用者peter、john 不得变更目录 使用者的预设目录为/home/username,若是我们不希望使用者在ftp 时能够 切换到上一层目录/home,则可参考以下步骤。 Step1. 修改/etc/vsftpd/vsftpd.conf 将底下三行 #chroot_list_enable=YES # (default follows) #chroot_list_file=/etc/vsftpd.chroot_list 改为 chroot_list_enable=YES # (default follows) chroot_list_file=/etc/vsftpd/chroot_list Step2. 新增一个档案: /etc/vsftpd/chroot_list 内容增加两行: peter john Step3. 重新启动vsftpd [root@home vsftpd]# /sbin/service vsftpd restart Shutting down vsftpd: OK ] Starting vsftpd for vsftpd: OK ] 若是peter 欲切换到根目录以外的目录,则会出现以下警告: ftp> cd /home 550 Failed to change directory. 3.2.4. 取消anonymous 登入 若是读者的主机不希望使用者匿名登入,则可参考以下步骤。 Step1. 修改/etc/vsftpd/vsftpd.conf 将 anonymous_enable=YES 改为 anonymous_enable=NO Step2. 重新启动vsftpd [root@home vsftpd]# /sbin/service vsftpd restart Shutting down vsftpd: OK ] Starting vsftpd for vsftpd: OK ] 3.2.5. 安排欢迎话语 若是我们希望使用者在登入时,能够看到欢迎话语,可能包括对该主机的说明,或是目录的介绍,可参考以下步骤。 首先确定在/etc/vsftpd/vsftpd.conf 当中是否有底下这一行 dirmessage_enable=YES RedHat9 的默认值是有上面这行的。 接着,在各目录之中,新增名为.message 的档案,再这边假设有一个使用者test1,且此使用者的根目录下有个目录名为abc,那首先我们在/home/test1 之下新增.message,内容如下: Hello~ Welcome to the home directory This is for test only... 接着,在/home/test1/abc 的目录下新增.message,内容如下: Welcome to abc's directory This is subdir... 那么,当使用者test1 登入时,会看到以下讯息: 230- Hello~ Welcome to the home directory 230- 230- This is for test only... 230- 若是切换到abc 的目录,则会出现以下讯息: 250- Welcome to abc's directory 250- 250- This is subdir ... 3.2.6. 对于每一个联机,以独立的process 来运作 一般启动vsftp 时,我们只会看到一个名为vsftpd 的process 在运作,但若是读者希望每一个联机,都能以独立的process 来呈现,则可执行以下步骤。 Step1. 修改/etc/vsftpd/vsftpd.conf 新增底下一行 setproctitle_enable=YES Step2. 重新启动vsftpd [root@home vsftpd]# /sbin/service vsftpd restart Shutting down vsftpd: OK ] Starting vsftpd for vsftpd: OK ] 使用ps -ef 的指令,可以看告不同使用者联机的情形,如下图所示: [root@home vsftpd]# ps -ef|grep ftp root 2090 1 0 16:41 pts/0 00:00:00 vsftpd: LISTENER nobody 2120 2090 0 17:18 ? 00:00:00 vsftpd: 192.168.10.244: connected test1 2122 2120 0 17:18 ? 00:00:00 vsftpd: 192.168.10.244/test1: IDLE nobody 2124 2090 0 17:19 ? 00:00:00 vsftpd: 192.168.10.244: connected test2 2126 2124 0 17:19 ? 00:00:00 vsftpd: 192.168.10.244/test2: IDLE root 2129 1343 0 17:20 pts/0 00:00:00 grep ftp [root@home vsftpd]# 3.2.7. 限制传输档案的速度: 本机的使用者最高速度为200KBytes/s,匿名登入者所能使用的最高速度为50KBytes/s Step1. 修改/etc/vsftpd/vsftpd.conf 新增底下两行 anon_max_rate=50000 local_max_rate=200000 Step2. 重新启动vsftpd [root@home vsftpd]# /sbin/service vsftpd restart Shutting down vsftpd: OK ] Starting vsftpd for vsftpd: OK ] 在这边速度的单位为Bytes/s,其中anon_max_rate 所限制的是匿名登入的 使用者,而local_max_rate 所限制的是本机的使用者。VSFTPD 对于速度的限 制,范围大概在80%到120%之间,也就是我们限制最高速度为100KBytes/s, 但实际的速度可能在80KBytes/s 到120KBytes/s 之间,当然,若是频宽不足 时,数值会低于此限制。 3.2.8. 针对不同的使用者限制不同的速度: 假设test1 所能使用的最高速度为250KBytes/s,test2 所能使用的最高速度为500KBytes/s。 Step1. 修改/etc/vsftpd/vsftpd.conf 新增底下一行 user_config_dir=/etc/vsftpd/userconf Step2. 新增一个目录:/etc/vsftpd/userconf mkdir /etc/vsftpd/userconf Step3. 在/etc/vsftpd/userconf 之下新增一个名为test1 的档案 内容增加一行: local_max_rate=250000 Step4. 在/etc/vsftpd/userconf 之下新增一个名为test2 的档案 内容增加一行: local_max_rate=500000 Step5. 重新启动vsftpd [root@home vsftpd]# /sbin/service vsftpd restart Shutting down vsftpd: OK ] Starting vsftpd for vsftpd: OK ] 3.2.9-1. 建置一个防火墙下的ftp server,使用PORT FTP mode: 预设的ftp port:21 以及ftp data port:20 启动VSFTPD 之后执行以下两行指令,只允许port 21 以及port 20 开放,其它关闭。 iptables -A INPUT -p tcp -m multiport --dport 21,20 -j ACCEPT iptables -A INPUT -p tcp -j REJECT --reject-with tcp-reset 3.2.9-2. 建置一个防火墙下的ftp server,使用PORT FTP mode: ftp port:2121 以及ftp data port:2020 Step1. 执行以下两行指令,只允许port 2121 以及port 2020 开放,其它关闭。 iptables -A INPUT -p tcp -m multiport --dport 2121,2020 -j ACCEPT iptables -A INPUT -p tcp -j REJECT --reject-with tcp-reset Step2. 修改/etc/vsftpd/vsftpd.conf 新增底下两行 listen_port=2121 ftp_data_port=2020 Step3. 重新启动vsftpd [root@home vsftpd]# /sbin/service vsftpd restart Shutting down vsftpd: OK ] Starting vsftpd for vsftpd: OK ] 在这边要注意,8、9 两个例子中,ftp client(如cuteftp)的联机方式不能够选择passive mode,否则无法建立数据的联机。也就是读者可以连上ftp server,但是执行ls、get 等等的指令时,便无法运作。 3.2.10. 建置一个防火墙下的ftp server,使用PASS FTP mode: ftp port:2121 以及ftp data port 从9981 到9986。 Step1. 执行以下两行指令,只允许port 2121 以及port 9981-9990 开放,其它关闭。 iptables -A INPUT -p tcp -m multiport --dport 2121,9981,9982,9983,9984,9985,9986,9987,9988,9989,9990 -j ACCEPT iptables -A INPUT -p tcp -j REJECT --reject-with tcp-reset Step2. 修改/etc/vsftpd/vsftpd.conf 新增底下四行 listen_port=2121 pasv_enable=YES pasv_min_port=9981 pasv_max_port=9986 Step3. 重新启动vsftpd [root@home vsftpd]# /sbin/service vsftpd restart Shutting down vsftpd: OK ] Starting vsftpd for vsftpd: OK ] 在这边要注意,在10 这个例子中,ftp client(如cuteftp)的联机方式必须选择passive mode,否则无法建立数据的联机。也就是读者可以连上ftp server,但是执行ls,get 等等的指令时,便无法运作。 3.2.11. 将vsftpd 与TCP_wrapper 结合 若是读者希望直接在/etc/hosts.allow 之中定义允许或是拒绝的来源地址,可执行以下步骤。这是简易的防火墙设定。 Step1. 确定/etc/vsftpd/vsftpd.conf 之中tcp_wrappers 的设定为YES,如下图所 示: tcp_wrappers=YES 这是RedHat9 的默认值,基本上不需修改。 Step2. 重新启动vsftpd [root@home vsftpd]# /sbin/service vsftpd restart Shutting down vsftpd: OK ] Starting vsftpd for vsftpd: OK ] Step3. 设定/etc/hosts.allow,譬如提供111.22.33.4 以及10.1.1.1 到10.1.1.254 连 线,则可做下图之设定: vsftpd : 111.22.33.4 10.1.1. : allow ALL : ALL : DENY 3.2.12. 将vsftpd 并入XINETD 若是读者希望将vsftpd 并入XINETD 之中,也就是7.x 版的预设设定,那 么读者可以执行以下步骤。 Step1. 修改/etc/vsftpd/vsftpd.conf 将 listen=YES 改为 listen=NO Step2. 新增一个档案: /etc/xinetd.d/vsftpd 内容如下: service vsftpd { disable = no socket_type = stream wait = no user = root server = /usr/sbin/vsftpd port = 21 log_on_success += PID HOST DURATION log_on_failure += HOST } Step3. 重新启动xinetd [root@home vsftpd]# /sbin/service xinetd restart Stopping xinetd: OK ] Starting xinetd: OK ] 3.2.3 设定档说明 在范例中,有些省略的设定可以在这边找到,譬如联机的总数、同一个位址的联机数、显示档案拥有者的名称等等,希望读者细读后,可以做出最适合自己的设定。 格式 vsftpd.conf 的内容非常单纯,每一行即为一项设定。若是空白行或是开头为#的一行,将会被忽略。内容的格式只有一种,如下所示 option=value 要注意的是,等号两边不能加空白,不然是不正确的设定。 ===ascii 设定===================== ascii_download_enable 管控是否可用ASCII 模式下载。默认值为NO。 ascii_upload_enable 管控是否可用ASCII 模式上传。默认值为NO。 ===个别使用者设定=================== chroot_list_enable 如果启动这项功能,则所有的本机使用者登入均可进到根目录之外的数据夹,除了列 在/etc/vsftpd.chroot_list 之中的使用者之外。默认值为NO。 userlist_enable 用法:YES/NO 若是启动此功能,则会读取/etc/vsftpd.user_list 当中的使用者名称。此项功能可以在询问密码前就出现失败讯息,而不需要检验密码的程序。默认值为关闭。 userlist_deny 用法:YES/NO 这个选项只有在userlist_enable 启动时才会被检验。如果将这个选项设为YES,则在/etc/vsftpd.user_list 中的使用者将无法登入 若设为NO , 则只有在 /etc/vsftpd.user_list 中的使用者才能登入。而且此项功能可以在询问密码前就出现错误讯息,而不需要检验密码的程序。 user_config_dir 定义个别使用者设定文件所在的目录,例如定义user_config_dir=/etc/vsftpd/userconf,且主机上有使用者test1,test2,那我们可以在user_config_dir 的目录新增文件名为test1 以及test2。若是test1 登入,则会读取user_config_dir 下的test1 这个档案内的设定。默认值为无。 ===欢迎语设定===================== dirmessage_enable 如果启动这个选项,使用者第一次进入一个目录时,会检查该目录下是否有.message这个档案,若是有,则会出现此档案的内容,通常这个档案会放置欢迎话语,或是对该目录的说明。默认值为开启。 banner_file 当使用者登入时,会显示此设定所在的档案内容,通常为欢迎话语或是说明。默认值为无。 ftpd_banner 这边可定义欢迎话语的字符串,相较于banner_file 是档案的形式,而ftpd_banner 是字串的格式。预设为无。 ===特殊安全设定==================== chroot_local_user 如果设定为YES,那么所有的本机的使用者都可以切换到根目录以外的数据夹。预设值为NO。 hide_ids 如果启动这项功能,所有档案的拥有者与群组都为ftp,也就是使用者登入使用ls -al之类的指令,所看到的档案拥有者跟群组均为ftp。默认值为关闭。 ls_recurse_enable 若是启动此功能,则允许登入者使用ls -R 这个指令。默认值为NO。 write_enable 用法:YES/NO 这个选项可以控制FTP 的指令是否允许更改file system,譬如STOR、DELE、 RNFR、RNTO、MKD、RMD、APPE 以及SITE。预设是关闭。 setproctitle_enable 用法:YES/NO 启动这项功能,vsftpd 会将所有联机的状况已不同的process 呈现出来,换句话说,使用ps -ef 这类的指令就可以看到联机的状态。默认值为关闭。 tcp_wrappers 用法:YES/NO 如果启动,则会将vsftpd 与tcp wrapper 结合,也就是可以在/etc/hosts.allow 与/etc/hosts.deny 中定义可联机或是拒绝的来源地址。 pam_service_name 这边定义PAM 所使用的名称,预设为vsftpd。 secure_chroot_dir 这个选项必须指定一个空的数据夹且任何登入者都不能有写入的权限,当vsftpd 不需要file system 的权限时,就会将使用者限制在此数据夹中。默认值为/usr/share/empty ===纪录文件设定===================== xferlog_enable 用法:YES/NO 如果启动,上传与下载的信息将被完整纪录在底下xferlog_file 所定义的档案中。预设为开启。 xferlog_file 这个选项可设定纪录文件所在的位置,默认值为/var/log/vsftpd.log。 xferlog_std_format 如果启动,则纪录文件将会写为xferlog 的标准格式,如同wu-ftpd 一般。默认值为关闭。 ===逾时设定====================== accept_timeout 接受建立联机的逾时设定,单位为秒。默认值为60。 connect_timeout 响应PORT 方式的数据联机的逾时设定,单位为秒。默认值为60。 data_connection_timeout 建立数据联机的逾时设定。默认值为300 秒。 idle_session_timeout 发呆的逾时设定,若是超出这时间没有数据的传送或是指令的输入,则会强迫断线,单位为秒。默认值为300。 ===速率限制====================== anon_max_rate 匿名登入所能使用的最大传输速度,单位为每秒多少bytes,0 表示不限速度。默认值为0。 local_max_rate 本机使用者所能使用的最大传输速度,单位为每秒多少bytes,0 表示不限速度。预设值为0。 ===新增档案权限设定================== anon_umask 匿名登入者新增档案时的umask 数值。默认值为077。 file_open_mode 上传档案的权限,与chmod 所使用的数值相同。默认值为0666。 local_umask 本机登入者新增档案时的umask 数值。默认值为077。 ===port 设定====================== connect_from_port_20 用法:YES/NO 若设为YES,则强迫ftp-data 的数据传送使用port 20。默认值为YES。 ftp_data_port 设定ftp 数据联机所使用的port。默认值为20。 listen_port FTP server 所使用的port。默认值为21。 pasv_max_port 建立资料联机所可以使用port 范围的上界,0 表示任意。默认值为0。 pasv_min_port 建立资料联机所可以使用port 范围的下界,0 表示任意。默认值为0。 ===其它======================== anon_root 使用匿名登入时,所登入的目录。默认值为无。 local_enable 用法:YES/NO 启动此功能则允许本机使用者登入。默认值为YES。 local_root 本机使用者登入时,将被更换到定义的目录下。默认值为无。 text_userdb_names 用法:YES/NO 当使用者登入后使用ls -al 之类的指令查询该档案的管理权时,预设会出现拥有者的UID,而不是该档案拥有者的名称。若是希望出现拥有者的名称,则将此功能开启。默认值为NO。 pasv_enable 若是设为NO,则不允许使用PASV 的模式建立数据的联机。默认值为开启。 ===更换档案所有权=================== chown_uploads 用法:YES/NO 若是启动,所有匿名上传数据的拥有者将被更换为chown_username 当中所设定的使用者。这样的选项对于安全及管理,是很有用的。默认值为NO。 chown_username 这里可以定义当匿名登入者上传档案时,该档案的拥有者将被置换的使用者名称。预设值为root。 ===guest 设定===================== guest_enable 用法:YES/NO 若是启动这项功能,所有的非匿名登入者都视为guest。默认值为关闭。 guest_username 这里将定义guest 的使用者名称。默认值为ftp。 ===anonymous 设定================== anonymous_enable 用法:YES/NO 管控使否允许匿名登入,YES 为允许匿名登入,NO 为不允许。默认值为YES。 no_anon_password 若是启动这项功能,则使用匿名登入时,不会询问密码。默认值为NO。 anon_mkdir_write_enable 用法:YES/NO 如果设为YES,匿名登入者会被允许新增目录,当然,匿名使用者必须要有对上层目录的写入权。默认值为NO。 anon_other_write_enable 用法:YES/NO 如果设为YES,匿名登入者会被允许更多于上传与建立目录之外的权限,譬如删除或是更名。默认值为NO。 anon_upload_enable 用法:YES/NO 如果设为YES,匿名登入者会被允许上传目录的权限,当然,匿名使用者必须要有对上层目录的写入权。默认值为NO。 anon_world_readable_only 用法:YES/NO 如果设为YES,匿名登入者会被允许下载可阅读的档案。默认值为YES。 ftp_username 定义匿名登入的使用者名称。默认值为ftp。 deny_email_enable 若是启动这项功能,则必须提供一个档案/etc/vsftpd.banner_emails,内容为email address。若是使用匿名登入,则会要求输入email address,若输入的email address 在此档案内,则不允许联机。默认值为NO。 ===Standalone 选项================== listen 用法:YES/NO 若是启动,则vsftpd 将会以独立运作的方式执行,若是vsftpd 独立执行,如RedHat9的默认值,则必须启动 若是vsftpd 包含在xinetd 之中,则必须关闭此功能,如RedHat8。在RedHat9 的默认值为YES。 listen_address 若是vsftpd 使用standalone 的模式,可使用这个参数定义使用哪个IP address 提供这项服务,若是主机上只有定义一个IP address,则此选项不需使用,若是有多个IP address,可定义在哪个IP address 上提供ftp 服务。若是不设定,则所有的IP address均会提供此服务。默认值为无。 max_clients 若是vsftpd 使用standalone 的模式,可使用这个参数定义最大的总联机数。超过这个数目将会拒绝联机,0 表示不限。默认值为0。 max_per_ip 若是vsftpd 使用standalone 的模式,可使用这个参数定义每个ip address 所可以联机的数目。超过这个数目将会拒绝联机,0 表示不限。默认值为0。 ============================= 3.2.4 FTP 数字代码的意义 110 重新启动标记应答。 120 服务在多久时间内ready。 125 数据链路埠开启,准备传送。 150 文件状态正常,开启数据连接端口。 200 命令执行成功。 202 命令执行失败。 211 系统状态或是系统求助响应。 212 目录的状态。 213 文件的状态。 214 求助的讯息。 215 名称系统类型。 220 新的联机服务ready。 221 服务的控制连接埠关闭,可以注销。 225 数据连结开启,但无传输动作。 226 关闭数据连接端口,请求的文件操作成功。 227 进入passive mode。 230 使用者登入。 250 请求的文件操作完成。 257 显示目前的路径名称。 331 用户名称正确,需要密码。 332 登入时需要账号信息。 350 请求的操作需要进一部的命令。 421 无法提供服务,关闭控制连结。 425 无法开启数据链路。 426 关闭联机,终止传输。 450 请求的操作未执行。 451 命令终止:有本地的错误。 452 未执行命令:磁盘空间不足。 500 格式错误,无法识别命令。 501 参数语法错误。 502 命令执行失败。 503 命令顺序错误。 504 命令所接的参数不正确。 530 未登入。 532 储存文件需要账户登入。 550 未执行请求的操作。 551 请求的命令终止,类型未知。 552 请求的文件终止,储存位溢出。 553 未执行请求的的命令,名称不正确。
1. 什么是grub grub 是一个多重启动管理器。grub是GRand Unified Bootloader的缩写,它可以在多个操作系统共存时选择引导哪个系统。它可以引导的操作系包括linux,FreeBSD,Solaris,NetBSD,BeOSi,OS/2,Windows95/98,Windows NT,Windows2000。它可以载入操作系统的内核和初始化操作系统(如Linux,FreeBSD),或者把引导权交给操作系统(如Windows 98)来完成引导。 2. grub的特点 grub可以代替lilo来完成对Linux的引导,特别适用于linux与其它操作系统共存情况,与lilo相比,它有以下特点: 支持大硬盘 现在大多数Linux发行版本的lilo都有同样的一个问题:根分区(/boot分区)不能分在超过1024柱面的地方,一般是在8.4G左右的地方,否则lilo不能安装,或者安装后不能正确引导系统。而grub就不会出现这种情况,只要安装时你的大硬盘是在LBA模式下,grub就可以引导根分区在8G以外的操作系统。 支持开机画面 grub支持在引导开机的同时显示一个开机画面。对于玩家来说,这样可以制作自己的个性化开机画面;对于PC厂商,这样可以在开机时显示电脑的一些信息和厂商的标志等。grub支持640x480,800x600,1024x768各种模式的开机画面,而且可以自动侦测选择最佳模式,与Windows那320x400的开机画面不可同日而语。 两种执行模式 grub不但可以通过配置文件进行例行的引导,还可以在选择引导前动态改变引导时的参数,还可以动态加载各种设备。例如你在Linux下编译了一个新的核心,但不能确定它能不能工作,你就可以在引导时动态改变grub的参数,尝试装载这个新的核心进行使用。Grub的命令行有非常强大的功能,而且支持如bash或doskey一样的历史功能,你可以用上下键来寻找以前的命令。 菜单式选择 在lilo下,你需要手工输入操作系统的名字来引导不同的操作系统。而grub使用一个菜单来选择不同的系统进行引导。你还可以自己配置各种参数,如延迟时间,默认操作系统等。 分区位置改变后不必重新配置 lilo是通过读取硬盘上的绝对扇区来装入操作系统,因此每次分区改变都必须重新配置lilo,例如你用PQ magic调整了分区的大小,那lilo在你重新配置好之前就不能引导这个分区的操作系统了。而grub是通过文件系统直接把核心读取到内存,因此只要操作系统核心的路径没有改变,grub就可以引导系统。 除此之外,Grub还有许多非常强大的功能。例如支持多种外部设备,动态装载操作系统内核,甚至可以通过网络装载操作系统核心。Grub支持多种文件系统,支持多种可执行文件格式,支持自动解压,可以引导不支持多重引导的操作系统等。 3. grub的使用 安装grub 如果已经安装了蓝点Linux2.0则grub是默认安装的。要把grub重新安装到主引导扇区上,只需要简单打入makebootable命令就可以了。 制作grub启动盘 首先确定grub已经安装,然后进入grub的目录,键入: #cd /boot/grub 放入一张软盘,然后敲入命令: #dd if=stage1 of=/dev/fd0 bs=512 count=1 #dd if=/stage2 of=/dev/fd0 bs512 seek=1 这样就可以做好一张启动盘了。 开机 安装了grub开机后会出现一个菜单,列出所有的启动选项。如果设置了启动画面则会显示启动画面,按Esc键则可以取消启动画面显示菜单选项。蓝点Linux所带的grub的命令提示是全中文的,在菜单下面详细列出如按e是编辑启动命令,按c是使用命令行等。用上下键可以选择菜单项,按回车启动所选项。按e键可以编辑所选项的启动命令,你可以用这个功能临时改变你的系统的启动参数,参见配置grub一节。按c键则进入命令行模式。 在命令行模式下可以打入命令直接执行,例如你可以敲入poweroff关闭计算机。按Tab键可以列出所有支持的命令。蓝点Linux已经把grub汉化了,其中一部分命令敲入名字后会给出中文提示,显示命令的用法和参数。 4. 配置grub grub启动时会在/boot/grub/中寻找一个名字为menu.lst的配置文件,如果找不到此文件则不进入菜单模式而直接进入命令行模式。 menu.lst 是一个文本文件,你可以用任何一个文本编辑器来打开它。每一行代表一个配置命令,如果一行的第一个字符为井号"#"则这一行为注释,你可以简单地用增加或减少注释行来改变配置。 编辑menu.lst,一般会有以下各行 timeout second 设定在second秒之后引导默认的操作系统。 蓝点Linux默认是timeout 5,就是5秒没有其他指令就引导系统,如果设成-1,则grub会一直等待直到用户选择一个选项为止。 default num 默认启动第num+1行选项,也就说default=0则默认启动菜单第一行的操作系统,default=1则启动第2行的系统,如此类推。 splash pathname/filename 指出开机画面的文件所存放的路径和文件名,如 splash /boot/logo/800x600x8.img 是指用在/boot/logo路径下的800x600.img文件作为开机画面 title OSname title 后面的字符就是你在菜单项上所看见的选项,你可以写上操作系统的名字和描述,如用 title BluePoint Linux, Single Mode 代表这一选项是引导蓝点Linux的单用户模式。 下面结合两个系统引导描述来解释几个引导选项的意义 title BluePoint Linux, Default Mode root (hd0,1) kernel /boot/vmlinuz vga=auto root=/dev/hda2 hd0是指第一个硬盘(主硬盘) (hd0,1)是指第一个硬盘的第二个分区。 kernel /boot/vmlinuz 是指出Linux核心的路径在/boot/vmlinuz中。vga=auto 是设定显示模式,root=/dev/hda2是指把第一个硬盘的第二个分区作为根挂载点("/")。 title Microsoft Windows root (hd1,0) chainloader (hd1,0)+1 root (hd1,0)这是指第二个硬盘(从硬盘)上第一个分区 chainloader (hd1,0)+1 装入一个扇区的数据然后把引导权交给它。 5. 从软盘启动grub 制作启动盘后可以用软盘启动引导硬盘上的操作系统 插入制作好的启动软盘,进入BIOS设定软盘启动。软盘启动成功后就会进入grub的命令行模式 grub> 要启动一个操作系统,首先指定引导哪个分区上的系统,例如要引导指第一个硬盘上的第一个分区的操作系统,先键入 grub>root (hd0,0) 接着如果要启动的是Windows系统,键入 grub>chainloader (hd0,0)+1 注意(hd0,0)要随着硬盘和分区的不同而改变数字。 如果要引导Linux或其他系统,应键入 grub>kernel (hd0,0)/boot/vmlinuz root=/dev/hda1 注意hda1参数也要随着硬盘和分区的不同而改变,如从第二个硬盘的第一个分区引导则用hdb1。 最后敲入boot就可以启动系统了。 在任何时候不能确定命令或者命令的参数都可以按Tab获得相关的帮助。用上下键可以获得命令的历史记录。 其实这些命令就是menu.lst的启动描述,您也可以根据那些描述来自己键入启动命令,最后敲入boot就可以引导系统了。
|
|
|
| 日 | 一 | 二 | 三 | 四 | 五 | 六 |
---|
27 | 28 | 29 | 30 | 31 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
|
导航
统计
常用链接
留言簿(1)
随笔分类(32)
随笔档案(33)
搜索
最新评论
阅读排行榜
评论排行榜
|
|