OMG,到底在尋找什么..................
          (構造一個完美的J2EE系統所需要的完整知識體系)
          posts - 198,  comments - 37,  trackbacks - 0
          原貼地址http://blog.csdn.net/clearwater21cn/category/99145.aspx

          QuickServer開發指南(1)- 介紹?

          QuickServer是一個免費的開源Java庫,用于快速創建健壯的多線程、多客戶端TCP服務器應用程序。使用QuickServer,用戶可以只集中處理應用程序的邏輯/協議,從而方便的建立功能強大的服務器應用。該程序由Akshathkumar Shetty設計和實現。
          ??? QuickServer安裝目錄下的example中有演示其功能的例子,最新的例子和文檔可以通過網站 http://www.quickserver.orghttp://quickserver.sourceforge.net獲得。
          ??? 該指南適用于所有想要學習和使用QuickServer的人,閱讀該指南應具備基本的Java編程知識,基本的網絡和sockets方面的知識也會有所幫助

          1.?為什么需要QuickServer?
          ??? 無論何種編程語言,socket編程對程序員來說都不是一件容易的事,創建多線程、多客戶端的服務器socket更像一場惡夢了。在每個新的軟件中處理多socket連接,我們都要浪費大把時間編寫大量重復的代碼。QuickServer因而誕生——使用Java創建多線程、多客戶端服務器應用。

          2.?基本構造
          QuickServer在應用邏輯上為開發者提供了四個類
          o?ClientCommandHandler
          ??? 處理與客戶端的交互——使用字符串命令
          o?ClientObjectHandler [可選類]
          ??? 處理與客戶端的交互——使用對象命令
          o?Authenticator [可選類]
          ??? 客戶端驗證
          o?ClientData [可選類]
          ??? 客戶端數據載體(支持類)
          下面的圖表顯示了QuickServer庫的基本構造。QuickServer模塊上七個輻條表示七個方法:
          o?java.lang.String info()
          o?int getServiceState()
          o?boolean initService(java.lang.Object[] config)
          o?boolean startService()
          o?boolean resumeService()
          o?boolean suspendService()
          o?boolean stopService()


          ??? 與QuickServer模塊相連接的四個組件中只有ClientCommandHandler是必須的。
          ??? QuickServerConfig對象由initService()方法構建。它實現了QuickServer,在讀取XML配置后,QuickServerConfig用于QuickServer配置。
          ??? ClientHandler線程對象用于客戶端緩沖池。可選的ClientData類與ClientHandler類關聯,ClientHandler對象容器參考ClientCommandHandler,ClientObjectHandler(可選),Authenticator(可選)對象包含在QuickServer主函數中。
          ??? 注意:上圖中并未顯示QSAdminServer,它是圖中QuickServer的組成部分。

          3.?主要特點
          o?創建多線程、多客戶端TCP服務器應用程序
          o?支持安全服務的創建:SSL, TLS
          o?清楚的分離服務、協議、驗證邏輯
          o?GUI圖形界面遠程管理支持
          o?Command Shell對服務器的本地管理
          o?無須斷開客戶端連接的重啟或延遲服務
          o?為線程的再利用和大多數的使用對象建立緩沖池
          o?完全的日志支持(Java構建)
          o?支持發送和接收字符串、字節、二進制、序列化Java對象
          o?在同樣的xml中支持能夠存貯指定應用數據的XML配置
          o?支持通過IP地址限制服務
          o?支持基于XML的JDBC映射
          o?支持服務配置模式
          o?支持從xml加載/重新加載用于jar包
          o?在QuickServer中添加處理hooks
          o?指定允許的最大客戶端連接數
          o?在通常的TCP連接上支持談判安全連接
          o?支持鑒別和查詢客戶端
          o?附帶典型例子——FTPServer, CmdServer,EchoWebServer, ChatServer

          4.?1.4版的新功能
          o?為QuickServer添加安全模式:SSL, TLS
          o?添加SecureManagerLoader管理安全模式
          o?在通常的TCP連接上添加談判安全連接
          o?添加初始化服務hooks
          o?為通信添加二進制模式
          o?為QsAdminServer通信添加QSAdminAPI
          o?為QuickServer 添加findAllClientByKey
          o?添加ConnectionLostException類
          o?改進ClientHandler、安全配置
          o?新例子——XmlAdder:一個簡單的xml服務,可添加兩個整數
          o?新例子——PipeServer:一個簡單的重定向服務

          QuickServer開發指南(2)- 安裝

          1. 運行環境
          QuickServer 1.2以上的版本需要(其實在偶看來一個1.4版以上JDK足矣):
          ? 推薦1.4版以上Java虛擬機,最低1.3版(未經測試).
          ? Java Logging API(下列之一)
          o java.util.logging包 [JDK 1.4版自帶]
          o Lumberjack庫 [http://javalogging.sourceforge.net/]
          ? XML 解析器 (下列之一)
          o SAX (面向XML 2.0的API) [JDK 1.4版自帶]
          o JAXP (面向XML解析的Java API) 1.1 [JDK 1.4版自帶]
          o Xerces [http://xml.apache.org/xerces2-j]
          o Crimson [http://xml.apache.org/crimson]
          ? Jakarta公共組件{Digester, Pool}
          o 這些產品包含在Apache開發的軟件中(http://www.apache.org/)。Jar包都在以下的庫中:BeanUtils, Collections, Logging. [http://jakarta.apache.org/commons/components.html]. Apache軟件許可證在文件“apache_license.txt”中。

          2. 安裝
          ??? 目前最新的1.4.1版QuickServer可在http://www.quickserver.org/download.html下載。安裝QuickServer,假設安裝路徑為$INSTALL_PATH。
          ??? 在CLASSPATH中添加"$INSTALL_PATH\dist\QuickServer.jar",在PATH中添加"$INSTALL_PATH\bin"。
          ??? 另外測試socket的通訊軟件推薦SockTest,在http://www.ddost.com/soft/sockettest 可下載到最新版本。Windows自帶的telnet也可以進行測試。

          QuickServer開發指南(3)- 構建EchoServer?

          學習怎樣使用QuickServer庫的一個好的方法是學習它提供的例子。在QuickServer安裝路徑下的examples文件夾里有許多典型的例子。
          ??? 下面的章節里我們模仿其中的一個例子EchoServer來構建一個服務器。EchoServer是一個簡單的TCP服務器,主要功能是將用戶發送的字符串加上前綴"Echo :"后返回。雖然這個例子可用性不強,但它是一個對QuickServer所有特點的一個很好的示范。我們從構建一個最基本的服務器開始,以后慢慢給它添加新的功能。

          1.?代碼
          ??? 首先實現EchoServer最基本的功能:將用戶發送的字符串加上前綴"Echo :"后返回。
          ??? 在本地創建一個文件夾存放需要的代碼,如在c:\projects\中建立echoserver文件夾,然后創建一個類EchoServer.java:

          01 package echoserver;

          02

          03 import org.quickserver.net.*;

          04 import org.quickserver.net.server.*;

          05

          06 import java.io.*;

          07

          08 public class EchoServer {

          09 public static void main(String s[]) {

          10 QuickServer myServer =

          11 new QuickServer("echoserver.EchoCommandHandler");

          12 myServer.setPort(4123);

          13 myServer.setName("EchoServer v 1.0");

          14 try {

          15 myServer.startServer();

          16 } catch(AppException e){

          17 System.err.println("Error in server : "+e);

          18 }

          19 }

          20 }


          ??? 在第10行和第11行定義了一個QuickServer對象myServer,通過一個String對象"echoserver.EchoCommandHandler"聲明了要加載的類,這個類面向所有客戶端做命令處理器,實現了org.quickserver.net.server.ClientCommandHandler接口,我們即將創建。
          ??? 第12行設置了一個服務器端口用來做監聽,然后設置整個應用的名字(第13行)。最后啟動服務(第15行)。

          ??? 接下來為EchoServer創建一個實現org.quickserver.net.server.ClientCommandHandler接口的類EchoCommandHandler.java,用來處理服務器發送的命令。

          01 // EchoCommandHandler.java

          02 package echoserver;

          03

          04 import java.net.*;

          05 import java.io.*;

          06 import org.quickserver.net.server.ClientCommandHandler;

          07 import org.quickserver.net.server.ClientHandler;

          08

          09 public class EchoCommandHandler implements ClientCommandHandler {

          10

          11 public void gotConnected(ClientHandler handler)

          12 throws SocketTimeoutException, IOException {

          13 handler.sendClientMsg("+++++++++++++++++++++++++++++++");

          14 handler.sendClientMsg("| Welcome to EchoServer v 1.3 |");

          15 handler.sendClientMsg("| Send 'Quit' to exit |");

          16 handler.sendClientMsg("+++++++++++++++++++++++++++++++");

          17 }

          18 public void lostConnection(ClientHandler handler)

          19 throws IOException {

          20 handler.sendSystemMsg("Connection lost : " +

          21 handler.getSocket().getInetAddress());

          22 }

          23 public void closingConnection(ClientHandler handler)

          24 throws IOException {

          25 handler.sendSystemMsg("Closing connection : " +

          26 handler.getSocket().getInetAddress());

          27 }

          28

          29 public void handleCommand(ClientHandler handler, String command)

          30 throws SocketTimeoutException, IOException {

          31 if(command.equals("Quit")) {

          32 handler.sendClientMsg("Bye ;-)");

          33 handler.closeConnection();

          34 } else {

          35 handler.sendClientMsg("Echo : "+command);

          36 }

          37 }

          38 }


          ??? 根據QuickServer的要求,這個類必須實現ClientCommandHandler接口。
          ??? 當客戶端建立一個連接(11行),gotConnected()方法被調用。在這個方法里面,我們給客戶端發送歡迎文本(13-16行),這些文本使用通過ClientHandler的sendClientMsg()方法發送給客戶端。我們也會使用ClientHandler的sendSystemMessage()方法顯示客戶端連接的InetAddress(20-21,25-26行)。
          ??? handlerCommand()方法是ClientCommandHandler接口的核心方法,因為服務器接收客戶端發送的任何命令時都要調用該方法。在我們對這個方法的實現中,我們會檢查命令是否為"Quit"(31行),如果是,我們將發送一些提示文本表示服務器即將關閉連接,然后關閉連接(33行)。否則,將命令加上前綴"Echo :"返回給用戶。

          2.?運行和測試
          o?運行命令提示符程序(cmd.exe)
          o?進入代碼所在文件夾根目錄,如c:\projects
          o?編譯代碼? javac echoserver\*.java
          o?若無編譯錯誤,運行服務器:
          ??? set classpath=%classpath%;d:\QuickServer\dist\QuickServer.jar;.\(類所在文件夾)
          ??? java echoserver.EchoServer
          o?您將會看到如下信息:

          o?測試我們的服務器是否可以正常工作。再運行一個cmd程序,進入SocketTest.jar所在目錄,鍵入java -jar sockettest.jar命令,彈出一個窗口。在IP Address中輸入"127.0.0.1",在Port里輸入"4123",點擊"Connect"按鈕,將看到窗口中顯示如下圖的信息。


          ??? 若使用telnet,可鍵入命令:open localhost 4123
          ??? 在Message中輸入一些字符串,點擊"Send"按鈕,瀏覽器將會返回一個加了前綴"Echo :"的字符串。發送"Quit",服務器斷開連接。

          QuickServer開發指南(4)- 添加認證

          現在我們給剛剛創建的服務器添加認證功能。
          ??? 查看org.quickserver.net.server.QuickServer的文檔(docs文件夾下)你可以注意到里面有一個方法
          ??? public void setAuthenticator(java.lang.String authenticator)
          ??? 閱讀文檔可知此方法中的authenticator字符串是實現org.quickserver.net.server.Authenticator接口的方法的全名。
          ??? Authenticator接口有兩個實現:
          ??? org.quickserver.net.server.QuickAuthenticator:這個類用來驗證連接QuickServer的客戶端。它只用一個實例處理所有的QuickServer驗證。(推薦)
          ??? org.quickserver.net.server.ServerAuthenticator:這個類同樣用來驗證連接QuickServer的客戶端,但對每一個驗證的處理都會創建一個實例。
          ??? 接下來給EchoServer加驗證功能。簡單點,客戶端輸入的用戶名和密碼一致就算驗證通過。
          ??? 首先,在同樣的文件夾里創建一個驗證類:EchoServerQuickAuthenticator

          01 package echoserver;

          02

          03 import org.quickserver.net.server.*;

          04 import java.io.*;

          05

          06 public class EchoServerQuickAuthenticator extends QuickAuthenticator {

          07

          08 public boolean askAuthorisation(ClientHandler clientHandler)

          09 throws IOException {

          10 String username = askStringInput(clientHandler, "User Name :");

          11 String password = askStringInput(clientHandler, "Password :");

          12

          13 if(username==null || password ==null)

          14 return false;

          15

          16 if(username.equals(password)) {

          17 sendString(clientHandler, "Auth OK");

          18 return true;

          19 } else {

          20 sendString(clientHandler, "Auth Failed");

          21 return false;

          22 }

          23 }

          24 }

          ??? 這個類擴展了org.quickserver.net.server.QuickAuthenticator(第6行),在askAuthorisation()方法中(8行),通過askStringInput()方法要求客戶端輸入用戶名和密碼,并讀入客戶端輸入的信息(10-11行)。這個方法繼承自QuickAuthenticator。如果用戶名與密碼相等,發送正確信息并返回"true"(16-18行),否則發送錯誤信息并返回"false"(20-21行)。

          ??? 接下來我們要告訴QuickServer使用我們新創建的驗證類來做驗證器。修改前一章創建的EchoServer.java文件,代碼如下(粗體為修改的代碼):

          01 package echoserver;

          02

          03 import com.ddost.net.*;

          04 import com.ddost.net.server.*;

          05

          06 import java.io.*;

          07

          08 public class EchoServer {

          09

          10 public static void main(String s[]) {

          11

          12 QuickServer myServer =

          13 new QuickServer("echoserver.EchoCommandHandler");

          14myServer.setAuthenticator(

          15"echoserver.EchoServerQuickAuthenticator");

          16 myServer.setPort(4123);

          17 myServer.setName("EchoServer v 1.0");

          18try {

          19 myServer.startServer();

          20 } catch(AppException e){

          21 System.err.println("Error in server : "+e);

          22 }

          23 }

          24 }


          ??? OK,將修改好的文件編譯,按照前一章講述的方法運行程序。這次當我們點擊"Connect"時,瀏覽器會要求我們輸入用戶名和密碼。如果輸入的用戶名和密碼一致就可以登錄。如果輸入錯誤五次以上,瀏覽器會提示"-ERR Max Auth Try Reached"并自動斷開連接。這個次數和提示信息可以通過QuickServer類的setMaxAuthTry() 和 setMaxAuthTryMsg()修改。


          ??? 有時在驗證過程中我們可能需要中途退出而不是等待驗證結束,這時輸入"Quit"是不起作用的。我們可以這樣修改代碼,有兩個方法:
          ??? 一是從EchoServerQuickAuthenticator類中的askAuthorisation()方法拋出一個org.quickserver.net.AppException異常,代碼如下:
          ??? String username = askStringInput(clientHandler, "User Name :");
          ??? if (username != null &&
          ??????? username.equalsIgnoreCase("QUIT")) {
          ????? sendString(clientHandler, "Logged out.");
          ????? throw new AppException("Quit");
          }
          ??? 或者參考ClientHandler,關閉連接,代碼如下:
          ??? String username = askStringInput(clientHandler, "User Name :");
          ??? if (username != null &&
          ??????? username.equalsIgnoreCase("QUIT")) {
          ????? sendString(clientHandler, "Logged out.");
          ????? clientHandler.closeConnection();
          ????? return false;
          }
          ??? ClientHandler對象能夠提供很多客戶端連接的有用信息,如IP地址。更多信息請參考API文檔。

          注意:
          ??? o 不要在驗證器類中存貯任何客戶端相關信息,如果需要,必須存放在ClientData類中--下一章將講解該部分內容。
          ??? o 必須確認askAuthorisation()方法是線程安全的。

          QuickServer開發指南(5)- 客戶數據

          既然不能在ClientCommandHandler和ServerAuthenticator類中保存客戶數據,我們使用ClientData類的handleCommand()或askAuthorisation()方法來存儲所有的客戶端信息。
          ??? 示范一下這個特點有什么用。還是以EchoServer為例,當用戶發送"Hello"時,我們給他一個問候。如果用戶再發送"Hello",我們提醒他已經發了n次"Hello"。接下來定義ClientData類來存儲用戶名以及他向服務器發送"Hello"的次數。

          1.?代碼
          1.?在EchoServer中創建一個EchoServerData類

          01 //---- EchoServerData.java ----

          02?package echoserver;

          03

          04 import org.quickserver.net.server.*;

          05 import java.io.*;

          06

          07 public class EchoServerData implements ClientData {

          08 private int helloCount;

          09 private String username;

          10

          11 public void setHelloCount(int count) {

          12 helloCount = count;

          13 }

          14 public int getHelloCount() {

          15 return helloCount;

          16 }

          17

          18 public void setUsername(String username) {

          19 this.username = username;

          20 }

          21 public String getUsername() {

          22 return username;

          23 }

          24 }

          25 //--- end of code ---


          2.?告訴QuickServer用這個EchoServerData來做為它的ClientData類。
          ??? 修改前面創建的EchoServer.java,代碼如下:

          01 package echoserver;

          02

          03 import org.quickserver.net.*;

          04 import org.quickserver.net.server.*;

          05

          06 import java.io.*;

          07

          08 public class EchoServer {

          09 public static void main(String s[]) {

          10

          11 String cmd = "echoserver.EchoCommandHandler";

          12 String auth = "echoserver.EchoServerQuickAuthenticator";

          13 String data = "echoserver.EchoServerData";

          14

          15 QuickServer myServer = new QuickServer(cmd);

          16 myServer.setAuthenticator(auth);

          17 myServer.setClientData(data);

          18

          19 myServer.setPort(4123);

          20 myServer.setName("Echo Server v 1.0");

          21 try {

          22 myServer.startServer();

          23 } catch(AppException e){

          24 System.out.println("Error in server : "+e);

          25 }

          26 }

          27 }


          ??? 上面的代碼中,我們將配置信息寫入String對象來設置QuickServer。???

          3.?修改Authenticator類,也就是EchoServerAuthenticator類,讓它在ClientData對象中存儲用戶名。下面是修改后的代碼:

          01 package echoserver;

          02

          03 import org.quickserver.net.server.*;

          04 import java.io.*;

          05

          06 public class EchoServerQuickAuthenticator extends QuickAuthenticator {

          07

          08 public boolean askAuthorisation(ClientHandler clientHandler)

          09 throws IOException {

          10 String username = askStringInput(clientHandler, "User Name :");

          11 if(username!=null && username.equalsIgnoreCase("QUIT")) {

          12 sendString(clientHandler, "Logged out.");

          13 //close the connection

          14 clientHandler.closeConnection();

          15 return false;

          16 }

          17

          18 String password = askStringInput(clientHandler, "Password :");

          19

          20 if(username==null || password ==null)

          21 return false;

          22

          23 if(username.equals(password)) {

          24 sendString(clientHandler, "Auth OK");

          25 //store the username in ClientData

          26 EchoServerData data = (EchoServerData)clientHandler.getClientData();

          27 data.setUsername(username);

          28 return true;

          29 } else {

          30 sendString(clientHandler, "Auth Failed");

          31 return false;

          32 }

          33 }

          34 }

          4.?修改ClientCommandHandler實現類EchoCommandHandler。如果用戶發送"Hello",給他一個問候。如果他發送多次"Hello",告訴他已經發送了n次"Hello"。下面是修改后的代碼:

          01 // EchoCommandHandler.java

          02 package echoserver;

          03

          04 import java.net.*;

          05 import java.io.*;

          06 import org.quickserver.net.server.ClientCommandHandler;

          07 import org.quickserver.net.server.ClientHandler;

          08

          09 public class EchoCommandHandler implements ClientCommandHandler {

          10

          11 public void gotConnected(ClientHandler handler)

          12 throws SocketTimeoutException, IOException {

          13 handler.sendClientMsg("+++++++++++++++++++++++++++++++");

          14 handler.sendClientMsg("| Welcome to EchoServer v 1.0 |");

          15 handler.sendClientMsg("| Note: Password = Username |");

          16 handler.sendClientMsg("| Send 'Quit' to exit |");

          17 handler.sendClientMsg("+++++++++++++++++++++++++++++++");

          18 }

          19 public void lostConnection(ClientHandler handler)

          20 throws IOException {

          21 handler.sendSystemMsg("Connection lost : " +

          22 handler.getSocket().getInetAddress());

          23 }

          24 public void closingConnection(ClientHandler handler)

          25 throws IOException {

          26 handler.sendSystemMsg("Closing connection : " +

          27 handler.getSocket().getInetAddress());

          28 }

          29

          30 public void handleCommand(ClientHandler handler, String command)

          31 throws SocketTimeoutException, IOException {

          32 if(command.equals("Quit")) {

          33 handler.sendClientMsg("Bye ;-)");

          34 handler.closeConnection();

          35 } if(command.equalsIgnoreCase("hello")) {

          36 EchoServerData data = (EchoServerData) handler.getClientData();

          37 data.setHelloCount(data.getHelloCount()+1);

          38 if(data.getHelloCount()==1) {

          39 handler.sendClientMsg("Hello "+data.getUsername());

          40 } else {

          41 handler.sendClientMsg("You told Hello "+data.getHelloCount()+

          42 " times. ");

          43 }

          44 } else {

          45 handler.sendClientMsg("Echo : "+command);

          46 }

          47 }

          48 }


          5.?編譯改好的程序,運行,使用SocketTest測試。登錄后,發送"Hello",系統會給一個問候,再次發送"Hello",它將告訴你發送了多少次"Hello"。
          ?
          4.2?創建ClientData池

          ??? 現在我們知道ClientData可以正常工作了。但是對每一個連接QuickServer的客戶端都要創建一個新的ClientData對象,可能會造成性能上的瓶頸,尤其對性能要求較高的服務器來說。
          ??? 我們可以創建一個ClientData池對象,無論客戶端什么時候進行連接,都使用同一個對象。首先實現下面的接口:
          ??? org.quickserver.util.pool.PoolableObject
          ??? 查找QuickServer API文檔可以發現PoolableObject只有兩個必須實現的方法:
          ??? org.apache.commons.pool.PoolableObjectFactory屬于通常的工廠方法。
          ??? isPoolable()判斷對象是否可以成為池對象。

          PoolableObjectFactory
          org.apache.commons.pool.PoolableObjectFactory接口包含了以下方法:
          o?void activateObject(Object obj):重新初始化一個實例。
          o?void destroyObject(Object obj):銷毀一個不再需要的實例。
          o?Object makeObject():創建一個實例。
          o?void passivateObject(Object obj):禁止初始化一個實例。
          o?boolean validateObject(Object obj):確定一個實例是否安全。

          ??? 我們可以擴展一個基于無操作的實現來創建可"池"化的對象:
          ??? org.apache.commons.pool.BasePoolableObjectFactory
          ??? 這個類只有一個抽象方法makeObject()和一個validateObject()方法,它只返回true。
          ??? 我們來創建一個EchoServerPoolableData類。

          01 //---- EchoServerPoolableData.java ----

          02 package echoserver;

          03

          04 import org.quickserver.net.server.*;

          05 import java.io.*;

          06

          07 public class EchoServerPoolableData

          08 extends EchoServerData

          09 implements org.apache.commons.pool.PoolableObjectFactory {

          10

          11 public void activateObject(Object obj) {

          12 }

          13 public void destroyObject(Object obj) {

          14 if(obj==null) return;

          15 passivateObject(obj);

          16 obj = null;

          17 }

          18 public Object makeObject() {

          19 return new EchoServerPoolableData();

          20 }

          21 public void passivateObject(Object obj) {

          22 EchoServerPoolableData pd = (EchoServerPoolableData)obj;

          23 pd.setHelloCount(0);

          24 pd.setUsername(null);

          25 }

          26 public boolean validateObject(Object obj) {

          27 if(obj==null)

          28 return false;

          29 else

          30 return true;

          31 }

          32 }

          33 //--- end of code ---

          ??? 這個類擴展了我們的EchoServerData,然后我們實現了org.apache.commons.pool.BasePoolableObjectFactory,這個實現是簡單的不需要解釋了。
          ??? 現在我們需要告訴QuickServer使用這個類來代替原來的ClientData類。
          ??????? myServer.setClientData("echoserver.EchoServerPoolableData");
          ??? 編譯修改的程序,可能會報如下錯誤:
          ??????? package org.apache.commons.pool does not exist。
          ??? 這是因為編譯器不知道這個類。可以在環境變量中添加D:\QuickServer\dist\commons-pool.jar包,并在運行時
          ??? set classpath=%classpath%;d:\QuickServer\dist\QuickServer.jar; d:\QuickServer\dist\commons-pool.jar;.\(類所在文件夾)即可。

          posted on 2006-12-04 19:45 OMG 閱讀(1129) 評論(0)  編輯  收藏 所屬分類: Soket

          <2006年12月>
          262728293012
          3456789
          10111213141516
          17181920212223
          24252627282930
          31123456

          常用鏈接

          留言簿(1)

          隨筆分類

          隨筆檔案

          IT風云人物

          文檔

          朋友

          相冊

          經典網站

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 酒泉市| 云浮市| 广元市| 宜兰市| 淳化县| 邯郸市| 自治县| 城步| 黑水县| 越西县| 绥德县| 正宁县| 屏山县| 松潘县| 原阳县| 金山区| 西乌| 盐边县| 犍为县| 安阳县| 丰城市| 巍山| 汶川县| 苏尼特左旗| 阜新市| 铜川市| 黑山县| 黄梅县| 柞水县| 大宁县| 宁津县| 天峻县| 温州市| 微山县| 金门县| 稷山县| 北辰区| 太仆寺旗| 岗巴县| 文山县| 河源市|