存档

2009年6月 的存档

打印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类型,大小写转换,等等。这些都是大学计算机课程的课后练习题。

java

利用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