打印GB2312编码中的所有汉字

2009年6月30日
  1. for(int j=0xB0; j<0xF8; j++)
  2.         {
  3.             for(int i=0xA1;i<0xFF;i++)
  4.             {
  5.                 byte[] bytes = new byte[2];
  6.                 bytes[0] = (byte)j;
  7.                 bytes[1] = (byte)i;
  8.                 System.out.println(new String(bytes));
  9.             }
  10.         }

java基础

TOMCAT源码总结一

2009年6月28日

首先不得不说这个类org.apache.tomcat.util.net.JIoEndpoint,它负责所有的TCP请求连接,实现了一个服务器模式,启用一个后台监听线程,负责接收到来的socket,然后从线程池中取出响应的worker,扔给worker进行处理,自己继续监听。其次worker是一个负责处理socket的一个线程,就是它带着用户的请求开始进入Tomcat世界的,默认的worker总共有200个,即:最多200个线程。当处理完一个请求的时候,这个线程并不会销毁,而是进入wait阻塞,这个线程的对象也不会销毁,是进入了一个栈里面,对应workstack那个数据结构。每当接收线程拿到一个socket的时候,就先从栈里面拿出一个已有的线程对象,然后就利用该对象的assign方法,将这个socket给它,并调用notify重新唤醒这个worker的处理线程。以后我们做小型服务器的时候,可以借鉴它的实现方式。正在研究多线程的朋友,这个类绝对让你可以学的透彻!

相对应的还有一个org.apache.tomcat.util.net.NioEndpoint,这个和前面那个功能差不多,但是用了NIO包里的API,有一个最大的区别就是,接收线程接收一个socket之后,可能会将这个socket先放入缓存池,然后worker从池里面拿socket去处理,比前面那个类看起来功能和性能都会提升很多,不过代码行有2K多,相当复杂,设计不够精巧,有兴趣可以去研究下。

org.apache.tomcat.util.buf.MessageBytes:这是一个接近底层的字符串处理类,为什么说是接近底层,是因为socket接收进来的都是字节类型,而java用的是char或者String,这之间的转换涉及到编码问题和性能问题,所以凡是socket收进来的信息,全部都用这个类表示,只有当要输出字符串的时候,才会将里面的字节进行转换,实现一种延迟加载的懒模式,被Tomcat底层所使用的Request类,就是大量使用了这个类来存放数据。我们来小小窥视一下,Request类:

  1. private MessageBytes methodMB = MessageBytes.newInstance();
  2.     private MessageBytes unparsedURIMB = MessageBytes.newInstance();
  3.     private MessageBytes uriMB = MessageBytes.newInstance();
  4.     private MessageBytes decodedUriMB = MessageBytes.newInstance();
  5.     private MessageBytes queryMB = MessageBytes.newInstance();
  6.     private MessageBytes protoMB = MessageBytes.newInstance();
  7.  
  8.     // remote address/host
  9.     private MessageBytes remoteAddrMB = MessageBytes.newInstance();
  10.     private MessageBytes localNameMB = MessageBytes.newInstance();
  11.     private MessageBytes remoteHostMB = MessageBytes.newInstance();
  12.     private MessageBytes localAddrMB = MessageBytes.newInstance();
  13.     
  14.     private MimeHeaders headers = new MimeHeaders();

或许大家会觉得,构造出这么多的类,性能会高到哪里去,其实不是这样的,不停的构造和销毁对象的确会损耗相当的性能,但是一个对象被构造出来,可以重复利用,那就相当完美了,这个类就是如此的设计,其中有一个回收资源的方法,叫recycle(),这个方法可以清空里面的数组,清空里面的对象,而不会销毁自己本身,因为使用它的对象,只要调用recycle,以后又可以重复使用了。

MessageBytes其实内置了2个重要的类,org.apache.tomcat.util.buf.ByteChunk和org.apache.tomcat.util.buf.CharChunk,这2个类带我们回到了C时代,为什么这么说?因为它简直就是一个字符串处理类,一些眼熟的算法全部映入眼帘,比如字符转匹配算法,indexOf,startsWith,判断字符转是否相等,查找字符,等等,比之JDK提供的性能更好,功能更强大(这句话说过了,呵呵)

还有一个实用的值得学习的数据结构是,org.apache.tomcat.util.buf.Ascii,如果知道表驱动的朋友们,一定对这个类很熟悉了,判断大小写?判断是不是英文单词?判断是不是空白符?判断是不是数字,将字节类型转换为int、long类型,大小写转换,等等。这些都是大学计算机课程的课后练习题。

tomcat研究

利用NIO非阻塞方式制作浏览器代理

2009年6月28日

下面代码的大致思路是:传入一个socketServer得到的socket的,然后再建立一条到其他代理服务器的socket的,接着就是按照顺序来回倒数据,只要读入的数据不是-1,那么就有可能再读到数据,这2条通路的任何一条通路读入数据为-1,那么就结束。其次还有退出循环的可能就是,在读数据的时候发生异常,有2种情况会产生这种异常,要么浏览器认为没有数据可以读了,要么代理服务器那里认为没有数据可以写过来了,那么它们就会close它们各自的socket,此时我们再尝试读socket,就会报错:socket已经被断开。

  1. import java.io.IOException;
  2. import java.net.InetSocketAddress;
  3. import java.nio.ByteBuffer;
  4. import java.nio.channels.SocketChannel;
  5. import java.nio.charset.Charset;
  6.  
  7. /**
  8. * 提供一种非阻塞方式的网络连接,性能提高
  9. */
  10. public class SocketNioHandler {
  11.  
  12.     private InetSocketAddress endpoint;
  13.  
  14.     public SocketNioHandler() {
  15.     }
  16.  
  17.     public SocketNioHandler(InetSocketAddress endpoint) {
  18.         this.endpoint = endpoint;
  19.     }
  20.  
  21.     /**
  22.      * 此方法是线程安全的
  23.      */
  24.     @Override
  25.     public boolean process(SocketChannel socket) {
  26.         SocketChannel outSocket = null;
  27.         ByteBuffer buff = ByteBuffer.allocate(1024);
  28.  
  29.         try {
  30.             outSocket = SocketChannel.open(endpoint);
  31.             outSocket.configureBlocking(false);
  32.  
  33.             while (true) {
  34.  
  35.                 if (socket.read(buff) < 0) {
  36.                     break;
  37.                 } else {
  38.                     buff.flip();
  39.                     if (buff.limit() > 10)
  40.                         System.out.println(Charset.defaultCharset()
  41.                                 .decode(buff));
  42.                     buff.rewind();
  43.                     while (buff.remaining() != 0) {
  44.                         outSocket.write(buff);
  45.                     }
  46.                     buff.clear();
  47.                 }
  48.  
  49.                 if (outSocket.read(buff) < 0) {
  50.                     break;
  51.                 } else {
  52.                     buff.flip();
  53.                     while (buff.remaining() != 0) {
  54.                         socket.write(buff);
  55.                     }
  56.                     buff.clear();
  57.                 }
  58.  
  59.                 try {
  60.                     Thread.sleep(1);
  61.                 } catch (InterruptedException e) {
  62.                     ;
  63.                 }
  64.             }
  65.  
  66.         } catch (IOException e) {
  67.             ;
  68.         } finally {
  69.             try {
  70.                 socket.close();
  71.             } catch (IOException e) {
  72.                 e.printStackTrace();
  73.             }
  74.             try {
  75.                 outSocket.close();
  76.             } catch (IOException e) {
  77.                 e.printStackTrace();
  78.             }
  79.  
  80.         }
  81.  
  82.         return true;
  83.     }
  84.  
  85. }

java基础

深入研究ReentrantLock(重入锁)之引出话题篇

2009年5月30日

一直以来都想好好研究下ReentrantLock,她的独到魅力令我屡试不爽,无奈网上实在是没有太多的资料可以参考,于是自己开始深入研究它的内部实现机制,经过数天的研究,终于有点心得体会升华了,记录之……

synchronized原语和ReentrantLock在一般情况下没有什么区别,但是在非常复杂的同步应用中,请考虑使用ReentrantLock,特别是遇到下面2种需求的时候。
1.某个线程在等待一个锁的控制权的这段时间需要中断
2.需要分开处理一些wait-notify,ReentrantLock里面的Condition应用,能够控制notify哪个线程
3.具有公平锁功能,每个到来的线程都将排队等候
下面细细道来……

先说第一种情况,ReentrantLock的lock机制有2种,忽略中断锁和响应中断锁,这给我们带来了很大的灵活性。比如:如果A、B2个线程去竞争锁,A线程得到了锁,B线程等待,但是A线程这个时候实在有太多事情要处理,就是一直不返回,B线程可能就会等不及了,想中断自己,不再等待这个锁了,转而处理其他事情。这个时候ReentrantLock就提供了2种机制,第一,B线程中断自己(或者别的线程中断它),但是ReentrantLock不去响应,继续让B线程等待,你再怎么中断,我全当耳边风(synchronized原语就是如此);第二,B线程中断自己(或者别的线程中断它),ReentrantLock处理了这个中断,并且不再等待这个锁的到来,完全放弃。(如果你没有了解java的中断机制,请参考下相关资料,再回头看这篇文章,80%的人根本没有真正理解什么是java的中断,呵呵)

这里来做个试验,首先搞一个Buffer类,它有读操作和写操作,为了不读到脏数据,写和读都需要加锁,我们先用synchronized原语来加锁,如下:

  1. public class Buffer {
  2.  
  3.     private Object lock;
  4.  
  5.     public Buffer() {
  6.         lock = this;
  7.     }
  8.  
  9.     public void write() {
  10.         synchronized (lock) {
  11.             long startTime = System.currentTimeMillis();
  12.             System.out.println("开始往这个buff写入数据…");
  13.             for (;;)// 模拟要处理很长时间
  14.             {
  15.                 if (System.currentTimeMillis()
  16.                         - startTime > Integer.MAX_VALUE)
  17.                     break;
  18.             }
  19.             System.out.println("终于写完了");
  20.         }
  21.     }
  22.  
  23.     public void read() {
  24.         synchronized (lock) {
  25.             System.out.println("从这个buff读数据");
  26.         }
  27.     }
  28. }

接着,我们来定义2个线程,一个线程去写,一个线程去读。

  1. public class Writer extends Thread {
  2.  
  3.     private Buffer buff;
  4.  
  5.     public Writer(Buffer buff) {
  6.         this.buff = buff;
  7.     }
  8.  
  9.     @Override
  10.     public void run() {
  11.         buff.write();
  12.     }
  13.  
  14. }
  15.  
  16. public class Reader extends Thread {
  17.  
  18.     private Buffer buff;
  19.  
  20.     public Reader(Buffer buff) {
  21.         this.buff = buff;
  22.     }
  23.  
  24.     @Override
  25.     public void run() {
  26.  
  27.         buff.read();//这里估计会一直阻塞
  28.  
  29.         System.out.println("读结束");
  30.  
  31.     }
  32.  
  33. }

好了,写一个Main来试验下,我们有意先去“写”,然后让“读”等待,“写”的时间是无穷的,就看“读”能不能放弃了。

  1. public class Test {
  2.     public static void main(String[] args) {
  3.         Buffer buff = new Buffer();
  4.  
  5.         final Writer writer = new Writer(buff);
  6.         final Reader reader = new Reader(buff);
  7.  
  8.         writer.start();
  9.         reader.start();
  10.  
  11.         new Thread(new Runnable() {
  12.  
  13.             @Override
  14.             public void run() {
  15.                 long start = System.currentTimeMillis();
  16.                 for (;;) {
  17.                     //等5秒钟去中断读
  18.                     if (System.currentTimeMillis()
  19.                             - start > 5000) {
  20.                         System.out.println("不等了,尝试中断");
  21.                         reader.interrupt();
  22.                         break;
  23.                     }
  24.  
  25.                 }
  26.  
  27.             }
  28.         }).start();
  29.  
  30.     }
  31. }

我们期待“读”这个线程能退出等待锁,可是事与愿违,一旦读这个线程发现自己得不到锁,就一直开始等待了,就算它等死,也得不到锁,因为写线程要21亿秒才能完成 T_T ,即使我们中断它,它都不来响应下,看来真的要等死了。这个时候,ReentrantLock给了一种机制让我们来响应中断,让“读”能伸能屈,勇敢放弃对这个锁的等待。我们来改写Buffer这个类,就叫BufferInterruptibly吧,可中断缓存。

  1. import java.util.concurrent.locks.ReentrantLock;
  2.  
  3. public class BufferInterruptibly {
  4.  
  5.     private ReentrantLock lock = new ReentrantLock();
  6.  
  7.     public void write() {
  8.         lock.lock();
  9.         try {
  10.             long startTime = System.currentTimeMillis();
  11.             System.out.println("开始往这个buff写入数据…");
  12.             for (;;)// 模拟要处理很长时间
  13.             {
  14.                 if (System.currentTimeMillis()
  15.                         - startTime > Integer.MAX_VALUE)
  16.                     break;
  17.             }
  18.             System.out.println("终于写完了");
  19.         } finally {
  20.             lock.unlock();
  21.         }
  22.     }
  23.  
  24.     public void read() throws InterruptedException {
  25.         lock.lockInterruptibly();// 注意这里,可以响应中断
  26.         try {
  27.             System.out.println("从这个buff读数据");
  28.         } finally {
  29.             lock.unlock();
  30.         }
  31.     }
  32.  
  33. }

当然,要对reader和writer做响应的修改

  1. public class Reader extends Thread {
  2.  
  3.     private BufferInterruptibly buff;
  4.  
  5.     public Reader(BufferInterruptibly buff) {
  6.         this.buff = buff;
  7.     }
  8.  
  9.     @Override
  10.     public void run() {
  11.  
  12.         try {
  13.             buff.read();//可以收到中断的异常,从而有效退出
  14.         } catch (InterruptedException e) {
  15.             System.out.println("我不读了");
  16.         }
  17.        
  18.         System.out.println("读结束");
  19.  
  20.     }
  21.  
  22. }
  23.  
  24. /**
  25. * Writer倒不用怎么改动
  26. */
  27. public class Writer extends Thread {
  28.  
  29.     private BufferInterruptibly buff;
  30.  
  31.     public Writer(BufferInterruptibly buff) {
  32.         this.buff = buff;
  33.     }
  34.  
  35.     @Override
  36.     public void run() {
  37.         buff.write();
  38.     }
  39.  
  40. }
  41.  
  42. public class Test {
  43.     public static void main(String[] args) {
  44.         BufferInterruptibly buff = new BufferInterruptibly();
  45.  
  46.         final Writer writer = new Writer(buff);
  47.         final Reader reader = new Reader(buff);
  48.  
  49.         writer.start();
  50.         reader.start();
  51.  
  52.         new Thread(new Runnable() {
  53.  
  54.             @Override
  55.             public void run() {
  56.                 long start = System.currentTimeMillis();
  57.                 for (;;) {
  58.                     if (System.currentTimeMillis()
  59.                             - start > 5000) {
  60.                         System.out.println("不等了,尝试中断");
  61.                         reader.interrupt();
  62.                         break;
  63.                     }
  64.  
  65.                 }
  66.  
  67.             }
  68.         }).start();
  69.  
  70.     }
  71. }

这次“读”线程接收到了lock.lockInterruptibly()中断,并且有效处理了这个“异常”。好奇的读者,肯定要探个究竟,为什么ReentrantLock能做到这点,接下来,我们去迷宫探险吧……

java基础 , , ,

对象序列化为何要定义serialVersionUID的来龙去脉

2009年5月5日

在很多应用中,需要对某些对象进行序列化,让它们离开内存空间,入住物理硬盘,以便长期保存。比如最常见的是Web服务器中的Session对象,当有10万用户并发访问,就有可能出现10万个Session对象,内存可能吃不消,于是Web容器就会把一些seesion先序列化到内存,等要用了,再还原到对象中,说白了,就是能将一个2进制文件变成内存中的对象。在JAVA中,要实现这种机制,只要实现Serializable接口就可以了,先看下面这个简单例子,serialVersionUID稍后引出。我们先定义一个简单的Person类,然后创建这个对象,最后序列化它到一个文件。

  1. import java.io.Serializable;
  2.  
  3. public class Person implements Serializable {
  4.    
  5.     private String name;
  6.    
  7.     public String getName() {
  8.         return name;
  9.     }
  10.     public void setName(String name) {
  11.         this.name = name;
  12.     }
  13. }
  1. import java.io.FileInputStream;
  2. import java.io.FileOutputStream;
  3. import java.io.ObjectInputStream;
  4. import java.io.ObjectOutputStream;
  5.  
  6. public class WhySerialversionUID {
  7.  
  8. public static void main(String[] args) throws Exception {
  9.  
  10. //这里是把对象序列化到文件       
  11. Person crab = new Person();
  12. crab.setName("Mr.Crab");
  13.  
  14. ObjectOutputStream oo = new ObjectOutputStream
  15.     (new FileOutputStream("crab_file"));
  16. oo.writeObject(crab);
  17. oo.close();
  18.  
  19. //这里是把对象序列化到文件,我们先注释掉,一会儿用
  20. //ObjectInputStream oi = new ObjectInputStream
  21. //    (new FileInputStream("crab_file"));
  22. //Person crab_back = (Person) oi.readObject();
  23. //System.out.println("Hi, My name is " + crab_back.getName());
  24. //oi.close();
  25.  
  26.     }
  27. }

运行完后,我们发现有了一个crab_file文件,这个文件就保存这crab对象在内存中的形态。同样,我们把这部分代码注释掉,运行下面那段还原代码,发现,crab_file文件可以被转化为一个对象。

一切都那么顺利,但是如果在序列化之后,Person这个类发生了改变呢?比如,多了一个成员变量。我们做如下试验,还是先将对象序列化到一个文件中,之后在Person这个类中添加一个成员变量,如下:

  1. import java.io.Serializable;
  2.  
  3. public class Person implements Serializable {
  4.    
  5.     private String name;
  6.     //添加这么一个成员变量
  7.     private String address;
  8.    
  9.     public String getName() {
  10.         return name;
  11.     }
  12.     public void setName(String name) {
  13.         this.name = name;
  14.     }
  15. }

之后,我们再去运行一下还原,就发现运行出错了,会报如下错误:
Exception in thread “main” java.io.InvalidClassException: Person; local class incompatible: stream classdesc serialVersionUID = 8383901821872620925, local class serialVersionUID = -763618247875550322
意思就是说,文件流中的class和classpath中的class,也就是修改过后的class,不兼容了,处于安全机制考虑,程序抛出了错误,并且拒绝载入。那么如果我们真的有需求要在序列化后添加一个字段或者方法呢?应该怎么办?那就是自己去指定serialVersionUID。之前,在我们的例子中,我们是没有指定serialVersionUID的,那么java编译器会自动给这个class进行一个摘要算法,类似于指纹算法,只要这个文件多一个空格,得到的UID就会截然不同的,可以保证在这么多类中,这个编号是唯一的。所以,我们添加了一个字段后,由于没有显指定serialVersionUID,编译器又为我们生成了一个UID,当然和前面保存在文件中的那个不会一样了,于是就出现了2个号码不一致的错误。因此,只要我们自己指定了serialVersionUID,就可以在序列化后,去添加一个字段,或者方法,而不会影响到后期的还原,还原后的对象照样可以使用,而且还多了方法可以用,呵呵。但是serialVersionUID我们怎么去生成呢?你可以写1,也可以写2,都无所谓,但是最好还是按照摘要算法,生成一个惟一的指纹数字,eclipse可以自动生成的,jdk也自带了这个工具。一般写法类似于
private static final long serialVersionUID = -763618247875550322L;

java基础

iphone 2.X固件令人惊叹

2009年5月1日

iphone已经用了一年半了,自从1.13版本以来就再也没有刷机过了,感觉硬件水平不变的情况下,软件平台本身是不会有质的飞跃的,但是前几天刷机到2.21之后,我发现自己真的落伍了,没想到这个一代的老iphone还是能发挥的如此出色,现在的3方软件也是五花八门,层出不穷,比起以前每用一个软件就失望一次比起来,这次真是给我带来太多的惊喜,下面是截图。

首先是主页面
img_0001img_0030

地图导航,能找到我在哪个位置,要去哪里,怎么走…居然把GPS模仿的这么好
img_0006img_0004

另外,UCWEB,飞信,QQ,同花顺,彩信等常用软件都用的非常爽
img_0027img_0008img_0010img_0012img_0023img_0034

最大的进步莫过于游戏了,想1年半之前,iphone刚推出那会儿,啥游戏都没有,装个GBA、PS2模拟器就乐呵乐呵了,看看现在这么多的游戏,真是再次令人惊叹。感谢网龙公司为大家贡献的这些,呵呵。

大杂烩

myfaces的初始化是如何进行的

2009年5月1日

在看myfaces源码的时候,一直不明白javax.faces.webapp.FacesServlet中有一段

  1. public void init(ServletConfig servletConfig)
  2.             throws ServletException
  3.     {
  4.         if(log.isTraceEnabled()) log.trace("init begin");
  5.         _servletConfig = servletConfig;
  6.         _facesContextFactory = (FacesContextFactory)FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
  7.         //TODO: null-check for Weblogic, that tries to initialize Servlet before ContextListener
  8.  
  9.         //Javadoc says: Lifecycle instance is shared across multiple simultaneous requests, it must be implemented in a thread-safe manner.
  10.         //So we can acquire it here once:
  11.         LifecycleFactory lifecycleFactory = (LifecycleFactory)FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
  12.         _lifecycle = lifecycleFactory.getLifecycle(getLifecycleId());
  13.         if(log.isTraceEnabled()) log.trace("init end");
  14.     }

其中的FactoryFinder.getFactory是这样一段代码

  1. public static Object getFactory(String factoryName)
  2.             throws FacesException
  3.     {
  4.         if(factoryName == null)
  5.             throw new NullPointerException("factoryName may not be null");
  6.  
  7.         ClassLoader classLoader = getClassLoader();
  8.  
  9.         //This code must be synchronized because this could cause a problem when
  10.         //using update feature each time of myfaces (org.apache.myfaces.CONFIG_REFRESH_PERIOD)
  11.         //In this moment, a concurrency problem could happen
  12.         Map factoryClassNames = null;
  13.         Map<String, Object> factoryMap = null;
  14.        
  15.         synchronized(_registeredFactoryNames)
  16.         {
  17.             factoryClassNames = _registeredFactoryNames.get(classLoader);
  18.  
  19.             if (factoryClassNames == null)
  20.             {
  21.                 throw new IllegalStateException(message);
  22.             }

注意其中的 _registeredFactoryNames.get(classLoader),说明在javax.faces.webapp.FacesServlet之前_registeredFactoryNames已经构造好了,可是我查web.xml的时候,根本找不到其它类了,到底谁去初始化了_registeredFactoryNames呢?

其实是 WEB-INF/lib/myfaces-impl-1.2.6.jar 这个引入的包起了作用,这里面有2个.tld文件,tomcat等j2ee容器会扫描所有的classpath,遇到.tld文件,也会去里面执行的。在myfaces_core.tld中,除了定义了一些f:开头标签以外,就有一段监听器代码

  1. <listener>
  2.   <listener-class>org.apache.myfaces.webapp.StartupServletContextListener</listener-class>
  3. </listener>

这才是整个myfaces加载的爆炸点。以前struts的爆炸点都是在web.xml定义的servlet中的,这次放在了jar包里面,正是有点不习惯,要是仅仅想用里面的一些功能,还非得加载这个玩意了,呵呵。

jsf

一人周末

2009年4月30日

一个人的周末,自由也很寂寞;
手机为你,变成最依赖的玩具;

一个人的周末,期待变成泡沫;
思念暴走,像热带鱼一样游过;

一个人的摩卡,想象两个人的焦糖;
without爱装哲学的你,何处去流放我的幻想。

你说那边,忙忙碌碌风和日丽;
却不知道,我这里风大心也凉;

要你在身边,让雨停出太阳;
要你躺在肚皮上,让它告诉你,没有你我有多么的坚强。

悄悄许个愿望,变成拇指姑娘;
躲进你的口袋,陪你四处流浪;

你说要做我的muscle man,要我乖乖,等你归来;
我说我要许你一个未来,做你永远的only one。

此刻才明白,你对我的温柔,是我永远无法割舍的依赖。

YOYO作词于杭州下沙
CRAB 谱词于深圳龙岗

大杂烩

VC++的一些路径信息

2009年4月11日

executatble files:
C:\Program Files\Microsoft Visual Studio\Common\MSDev98\Bin
C:\Program Files\Microsoft Visual Studio\VC98\BIN
C:\Program Files\Microsoft Visual Studio\Common\TOOLS
C:\Program Files\Microsoft Visual Studio\Common\TOOLS\WINNT

include files:
C:\Program Files\Microsoft Visual Studio\VC98\INCLUDE
C:\Program Files\Microsoft Visual Studio\VC98\MFC\INCLUDE
C:\Program Files\Microsoft Visual Studio\VC98\ATL\INCLUDE

library files:
C:\Program Files\Microsoft Visual Studio\VC98\LIB
C:\Program Files\Microsoft Visual Studio\VC98\MFC\LIB

source files:
C:\Program Files\Microsoft Visual Studio\VC98\MFC\SRC
C:\Program Files\Microsoft Visual Studio\VC98\MFC\INCLUDE
C:\Program Files\Microsoft Visual Studio\VC98\ATL\INCLUDE
C:\Program Files\Microsoft Visual Studio\VC98\CRT\SRC

添加时要精确点,确保这些目录都找的到,而且后面不能有空格…

C/C++ ,

云缤纷,云满天(云计算漫谈之二)(转载)

2009年2月6日

前几天,写文章谈了谈从前的事儿,云之初,本无奈。

那么现在呢?倘或你仰头看,那是云满天,云缤纷。

这时候,你口中一定会随便哼唱出:“ 天边飘过故乡的云,它不停地向我召唤……”

无数的云在向我们召唤:

那朵叫做GOOGLE的云唱了:“快来吧,快来吧……云计算时代已经到来,云就是互联网,我们的云计算和互联网应用是可用性最好的,我们在开源里公开了我们很多技术,大家都来炒作吧,我们就是云计算的教父。” 但实际呢,无论是GFS还是MAP REDUCE,都不是google成功的关键,其核心的Borg,Google 则一直遮遮掩掩。

阅读全文…

大杂烩