亚洲人成电影网站国产精品 ,精品久久久久久亚洲精品,亚洲福利一区二区精品秒拍http://m.tkk7.com/tbest/category/32708.htmljava先(我應該為它寫點什么了?。?/description>zh-cnWed, 04 May 2011 21:33:00 GMTWed, 04 May 2011 21:33:00 GMT60(轉)reflecthttp://m.tkk7.com/tbest/articles/349537.htmlliujgliujgWed, 04 May 2011 15:16:00 GMThttp://m.tkk7.com/tbest/articles/349537.htmlhttp://m.tkk7.com/tbest/comments/349537.htmlhttp://m.tkk7.com/tbest/articles/349537.html#Feedback0http://m.tkk7.com/tbest/comments/commentRss/349537.htmlhttp://m.tkk7.com/tbest/services/trackbacks/349537.html 

import java.lang.reflect.Constructor;

import java.lang.reflect.Field;

import java.lang.reflect.Method;





/**

 * Java Reflection Cookbook

 *

 * 
@author Michael Lee

 * 
@since 2006-8-23

 * 
@version 0.1a

 
*/



public class Reflection {

    
/**

     * 得到某個對象的公共屬性

     *

     * 
@param owner, fieldName

     * 
@return 該屬性對象

     * 
@throws Exception

     *

     
*/

    
public Object getProperty(Object owner, String fieldName) throws Exception {

        Class ownerClass 
= owner.getClass();



        Field field 
= ownerClass.getField(fieldName);



        Object property 
= field.get(owner);



        
return property;

    }



    
/**

     * 得到某類的靜態公共屬性

     *

     * 
@param className   類名

     * 
@param fieldName   屬性名

     * 
@return 該屬性對象

     * 
@throws Exception

     
*/

    
public Object getStaticProperty(String className, String fieldName)

            
throws Exception {

        Class ownerClass 
= Class.forName(className);



        Field field 
= ownerClass.getField(fieldName);



        Object property 
= field.get(ownerClass);



        
return property;

    }





    
/**

     * 執行某對象方法

     *

     * 
@param owner

     *            對象

     * 
@param methodName

     *            方法名

     * 
@param args

     *            參數

     * 
@return 方法返回值

     * 
@throws Exception

     
*/

    
public Object invokeMethod(Object owner, String methodName, Object[] args)

            
throws Exception {



        Class ownerClass 
= owner.getClass();



        Class[] argsClass 
= new Class[args.length];



        
for (int i = 0, j = args.length; i < j; i++) {

            argsClass[i] 
= args[i].getClass();

        }



        Method method 
= ownerClass.getMethod(methodName, argsClass);



        
return method.invoke(owner, args);

    }





      
/**

     * 執行某類的靜態方法

     *

     * 
@param className

     *            類名

     * 
@param methodName

     *            方法名

     * 
@param args

     *            參數數組

     * 
@return 執行方法返回的結果

     * 
@throws Exception

     
*/

    
public Object invokeStaticMethod(String className, String methodName,

            Object[] args) 
throws Exception {

        Class ownerClass 
= Class.forName(className);



        Class[] argsClass 
= new Class[args.length];



        
for (int i = 0, j = args.length; i < j; i++) {

            argsClass[i] 
= args[i].getClass();

        }



        Method method 
= ownerClass.getMethod(methodName, argsClass);



        
return method.invoke(null, args);

    }







    
/**

     * 新建實例

     *

     * 
@param className

     *            類名

     * 
@param args

     *            構造函數的參數

     * 
@return 新建的實例

     * 
@throws Exception

     
*/

    
public Object newInstance(String className, Object[] args) throws Exception {

        Class newoneClass 
= Class.forName(className);



        Class[] argsClass 
= new Class[args.length];



        
for (int i = 0, j = args.length; i < j; i++) {

            argsClass[i] 
= args[i].getClass();

        }



        Constructor cons 
= newoneClass.getConstructor(argsClass);



        
return cons.newInstance(args);



    }





    

    
/**

     * 是不是某個類的實例

     * 
@param obj 實例

     * 
@param cls 類

     * 
@return 如果 obj 是此類的實例,則返回 true

     
*/

    
public boolean isInstance(Object obj, Class cls) {

        
return cls.isInstance(obj);

    }

    

    
/**

     * 得到數組中的某個元素

     * 
@param array 數組

     * 
@param index 索引

     * 
@return 返回指定數組對象中索引組件的值

     
*/

    
public Object getByArray(Object array, int index) {

        
return Array.get(array,index);

    }

}



liujg 2011-05-04 23:16 發表評論
]]>
面試基礎題目http://m.tkk7.com/tbest/articles/349532.htmlliujgliujgWed, 04 May 2011 14:24:00 GMThttp://m.tkk7.com/tbest/articles/349532.htmlhttp://m.tkk7.com/tbest/comments/349532.htmlhttp://m.tkk7.com/tbest/articles/349532.html#Feedback0http://m.tkk7.com/tbest/comments/commentRss/349532.htmlhttp://m.tkk7.com/tbest/services/trackbacks/349532.html
1.現在輸入n個數字,以逗號,分開;
然后可選擇升或者降序排序;
按提交鍵就在另一頁面顯示
  按什么排序,結果為,  ,
提供reset
答案(1)  public static String[] splitStringByComma(String source){
           if(source==null||source.trim().equals(""))
                   return null;
           StringTokenizer commaToker =  new StringTokenizer(source,",");
           String[] result = new String[commaToker.countTokens()];
           int i=0;
           while(commaToker.hasMoreTokens()){
                   result[i] = commaToker.nextToken();
                   i++;
           }
           return result;
  }
循環遍歷String數組
Integer.parseInt(String s)變成int類型
組成int數組
Arrays.sort(int[] a),
a數組升序
降序可以從尾部開始輸出

2.金額轉換,阿拉伯數字的金額轉換成中國傳統的形式如:
(¥1011)->(一千零一拾一元整)輸出。
3、繼承時候類的執行順序問題,一般都是選擇題,問你將會打印出什么?
答:父類:
package test;
public class FatherClass
{
public FatherClass()
{
System.out.println("FatherClass Create");
}
}
子類:
package test;
import test.FatherClass;
public class ChildClass extends FatherClass
{
public ChildClass()
{
System.out.println("ChildClass Create");
}
public static void main(String[] args)
{
FatherClass fc = new FatherClass();
ChildClass cc = new ChildClass();
}
}
輸出結果:
C:>java test.ChildClass
FatherClass Create
FatherClass Create
ChildClass Create

4、內部類的實現方式?
答:示例代碼如下:
package test;
public class OuterClass
{
** class InterClass
{
public InterClass()
{
System.out.println("InterClass Create");
}
}
public OuterClass()
{
InterClass ic = new InterClass();
System.out.println("OuterClass Create");
}
public static void main(String[] args)
{
OuterClass oc = new OuterClass();
}
}
輸出結果:
C:>java test/OuterClass
InterClass Create
OuterClass Create
再一個例題:
public class OuterClass {
** double d1 = 1.0;
//insert code here
}
You need to insert an inner class declaration at line 3. Which two inner class declarations are

valid?(Choose two.)
A. class InnerOne{
public static double methoda() {return d1;}
}
B. public class InnerOne{
static double methoda() {return d1;}
}
C. ** class InnerOne{
double methoda() {return d1;}
}
D. static class InnerOne{
protected double methoda() {return d1;}
}
E. abstract class InnerOne{
public abstract double methoda();
}
說明如下:
一.靜態內部類可以有靜態成員,而非靜態內部類則不能有靜態成員。 故 A、B 錯
二.靜態內部類的非靜態成員可以訪問外部類的靜態變量,而不可訪問外部類的非靜態變量;return d1 出錯。

故 D 錯
三.非靜態內部類的非靜態成員可以訪問外部類的非靜態變量。 故 C 正確
四.答案為C、E


5、Java 的通信編程,編程題(或問答),用JAVA SOCKET編程,讀服務器幾個字符,再寫入本地顯示?
答:Server端程序:
package test;
import java.net.*;
import java.io.*;
public class Server
{
** ServerSocket ss;
** Socket socket;
** BufferedReader in;
** PrintWriter out;
public Server()
{
try
{
ss=new ServerSocket(10000);
while(true)
{
socket = ss.accept();
String RemoteIP = socket.getInetAddress().getHostAddress();
String RemotePort = ":"+socket.getLocalPort();
System.out.println("A client come in!IP:"+RemoteIP+RemotePort);
in = new BufferedReader(new

InputStreamReader(socket.getInputStream()));
String line = in.readLine();
System.out.println("Cleint send is :" + line);
out = new PrintWriter(socket.getOutputStream(),true);
out.println("Your Message Received!");
out.close();
in.close();
socket.close();
}
}catch (IOException e)
{
out.println("wrong");
}
}
public static void main(String[] args)
{
new Server();
}
};
Client端程序:
package test;
import java.io.*;
import java.net.*;

public class Client
{
Socket socket;
BufferedReader in;
PrintWriter out;
public Client()
{
try
{
System.out.println("Try to Connect to 127.0.0.1:10000");
socket = new Socket("127.0.0.1",10000);
System.out.println("The Server Connected!");
System.out.println("Please enter some Character:");
BufferedReader line = new BufferedReader(new

InputStreamReader(System.in));
out = new PrintWriter(socket.getOutputStream(),true);
out.println(line.readLine());
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
System.out.println(in.readLine());
out.close();
in.close();
socket.close();
}catch(IOException e)
{
out.println("Wrong");
}
}
public static void main(String[] args)
{
new Client();
}
};
6、用JAVA實現一種排序,JAVA類實現序列化的方法(二種)?如在COLLECTION框架中,實現比較要實現什么樣的接口?
答:用插入法進行排序代碼如下
package test;
import java.util.*;
class InsertSort
{
ArrayList al;
public InsertSort(int num,int mod)
{
al = new ArrayList(num);
Random rand = new Random();
System.out.println("The ArrayList Sort Before:");
for (int i=0;i<num ;i++ )
{
al.add(new Integer(Math.abs(rand.nextInt()) % mod + 1));
System.out.println("al["+i+"]="+al.get(i));
}
}
public void SortIt()
{
Integer tempInt;
int MaxSize=1;
for(int i=1;i<al.size();i++)
{
tempInt = (Integer)al.remove(i);
if(tempInt.intValue()>=((Integer)al.get(MaxSize-1)).intValue())
{
al.add(MaxSize,tempInt);
MaxSize++;
System.out.println(al.toString());
} else {
for (int j=0;j<MaxSize ;j++ )
{
if

(((Integer)al.get(j)).intValue()>=tempInt.intValue())
{
al.add(j,tempInt);
MaxSize++;
System.out.println(al.toString());
break;
}
}
}
}
System.out.println("The ArrayList Sort After:");
for(int i=0;i<al.size();i++)
{
System.out.println("al["+i+"]="+al.get(i));
}
}
public static void main(String[] args)
{
InsertSort is = new InsertSort(10,100);
is.SortIt();
}
}
JAVA類實現序例化的方法是實現java.io.Serializable接口
Collection框架中實現比較要實現Comparable 接口和 Comparator 接口
7、編程:編寫一個截取字符串的函數,輸入為一個字符串和字節數,輸出為按字節截取的字符串。但是要保證漢字不被截半個,如"我ABC"4,應該截為"我AB",輸入"我ABC漢DEF",6,應該輸出為"我ABC"而不是"我ABC+漢的半個"。
答:代碼如下:
package test;

class SplitString
{
String SplitStr;
int SplitByte;
public SplitString(String str,int bytes)
{
SplitStr=str;
SplitByte=bytes;
System.out.println("The String is:′"+SplitStr+"′;SplitBytes="+SplitByte);
}
public void SplitIt()
{
int loopCount;
loopCount=(SplitStr.length()%SplitByte==0)?(SplitStr.length()/SplitByte):(SplitStr.length()/Split
Byte+1);
System.out.println("Will Split into "+loopCount);
for (int i=1;i<=loopCount ;i++ )
{
if (i==loopCount){
System.out.println(SplitStr.substring((i-1)*SplitByte,SplitStr.length()));
} else {
System.out.println(SplitStr.substring((i-1)*SplitByte,(i*SplitByte)));
}
}
}
public static void main(String[] args)
{
SplitString ss = new SplitString("test中dd文dsaf中男大3443n中國43中國人

0ewldfls=103",4);
ss.SplitIt();
}
}
8、JAVA多線程編程。 用JAVA寫一個多線程程序,如寫四個線程,二個加1,二個對一個變量減一,輸出。
希望大家補上,謝謝
9、STRING與STRINGBUFFER的區別。
答:STRING的長度是不可變的,STRINGBUFFER的長度是可變的。如果你對字符串中的內容經常進行操作,特別是內容要修改時,那么使用StringBuffer,如果最后需要String,那么使用StringBuffer的toString()方法
Jsp方面
1、jsp有哪些內置對象?作用分別是什么?
答:JSP共有以下9種基本內置組件(可與ASP的6種內部組件相對應):
 request 用戶端請求,此請求會包含來自GET/POST請求的參數
response 網頁傳回用戶端的回應
pageContext 網頁的屬性是在這里管理
session 與請求有關的會話期
application servlet 正在執行的內容
out 用來傳送回應的輸出
config servlet的構架部件
page JSP網頁本身
exception 針對錯誤網頁,未捕捉的例外
2、jsp有哪些動作?作用分別是什么?
答:JSP共有以下6種基本動作
jsp:include:在頁面被請求的時候引入一個文件。
jsp:useBean:尋找或者實例化一個JavaBean。
jsp:setProperty:設置JavaBean的屬性。
jsp:getProperty:輸出某個JavaBean的屬性。
jsp:forward:把請求轉到一個新的頁面。
jsp:plugin:根據瀏覽器類型為Java插件生成OBJECT或EMBED標記
3、JSP中動態INCLUDE與靜態INCLUDE的區別?
答:動態INCLUDE用jsp:include動作實現
<jsp:include page="included.jsp" flush="true" />它總是會檢查所含文件中的變化,適合用于包含動態頁面,并且可以帶參數
靜態INCLUDE用include偽碼實現,定不會檢查所含文件的變化,適用于包含靜態頁面
<%@ include file="included.htm" %>
4、兩種跳轉方式分別是什么?有什么區別?
答:有兩種,分別為:
<jsp:include page="included.jsp" flush="true">
<jsp:forward page= "nextpage.jsp"/>
前者頁面不會轉向include所指的頁面,只是顯示該頁的結果,主頁面還是原來的頁面。執行完后還會回來,相當于函數調用。并且可以帶參數.后者完全轉向新頁面,不會再回來。相當于go to 語句。
Servlet方面
1、說一說Servlet的生命周期?
答:servlet有良好的生存期的定義,包括加載和實例化、初始化、處理請求以及服務結束。這個生存期由javax.servlet.Servlet接口的init,service和destroy方法表達。
2、Servlet版本間(忘了問的是哪兩個版本了)的不同?
希望大家補上,謝謝
3、JAVA SERVLET API中forward() 與redirect()的區別?
答:前者僅是容器中控制權的轉向,在客戶端瀏覽器地址欄中不會顯示出轉向后的地址;后者則是完全的跳轉,瀏覽器將會得到跳轉的地址,并重新發送請求鏈接。這樣,從瀏覽器的地址欄中可以看到跳轉后的鏈接地址。所以,前者更加高效,在前者可以滿足需要時,盡量使用forward()方法,并且,這樣也有助于隱藏實際的鏈接。在有些情況下,比如,需要跳轉到一個其它服務器上的資源,則必須使用sendRedirect()方法。
4、Servlet的基本架構
public class ServletName extends HttpServlet {
public void doPost(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
}
public void doGet(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
}
}

Jdbc、Jdo方面
1、可能會讓你寫一段Jdbc連Oracle的程序,并實現數據查詢.
答:程序如下:
package hello.ant;
import java.sql.*;
public class jdbc
{
String dbUrl="jdbc:oracle:thin:@127.0.0.1:1521:orcl";
String theUser="admin";
String thePw="manager";
Connection c=null;
Statement conn;
ResultSet rs=null;
public jdbc()
{
try{
Class.forName("oracle.jdbc.driver.OracleDriver").newInstance();
c = DriverManager.getConnection(dbUrl,theUser,thePw);
conn=c.createStatement();
}catch(Exception e){
e.printStackTrace();
}
}
public boolean executeUpdate(String sql)
{
try
{
conn.executeUpdate(sql);
return true;
}
catch (SQLException e)
{
e.printStackTrace();
return false;
}
}
public ResultSet executeQuery(String sql)
{
rs=null;
try
{
rs=conn.executeQuery(sql);
}
catch (SQLException e)
{
e.printStackTrace();
}
return rs;
}
public void close()
{
try
{
conn.close();
c.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
public static void main(String[] args)
{
ResultSet rs;
jdbc conn = new jdbc();
rs=conn.executeQuery("select * from test");
try{
while (rs.next())
{
System.out.println(rs.getString("id"));
System.out.println(rs.getString("name"));
}
}catch(Exception e)
{
e.printStackTrace();
}
}
}
2、Class.forName的作用?為什么要用?
答:調用該訪問返回一個以字符串指定類名的類的對象。
3、Jdo是什么?
答:JDO是Java對象持久化的新的規范,為java data object的簡稱,也是一個用于存取某種數據倉庫中的對象的標準化API。JDO提供了透明的對象存儲,因此對開發人員來說,存儲數據對象完全不需要額外的代碼(如JDBC API的使用)。這些繁瑣的例行工作已經轉移到JDO產品提供商身上,使開發人員解脫出來,從而集中時間和精力在業務邏輯上。另外,JDO很靈活,因為它可以在任何數據底層上運行。JDBC只是面向關系數據庫(RDBMS)JDO更通用,提供到任何數據底層的存儲功能,比如關系數據庫、文件、XML以及對象數據庫(ODBMS)等等,使得應用可移植性更強。
4、在ORACLE大數據量下的分頁解決方法。一般用截取ID方法,還有是三層嵌套方法。
答:一種分頁方法
<%
int i=1;
int numPages=14;
String pages = request.getParameter("page") ;
int currentPage = 1;
currentPage=(pages==null)?(1):{Integer.parseInt(pages)}
sql = "select count(*) from tables";
ResultSet rs = DBLink.executeQuery(sql) ;
while(rs.next()) i = rs.getInt(1) ;
int intPageCount=1;
intPageCount=(i%numPages==0)?(i/numPages):(i/numPages+1);
int nextPage ;
int upPage;
nextPage = currentPage+1;
if (nextPage>=intPageCount) nextPage=intPageCount;
upPage = currentPage-1;
if (upPage<=1) upPage=1;
rs.close();
sql="select * from tables";
rs=DBLink.executeQuery(sql);
i=0;
while((i<numPages*(currentPage-1))&&rs.next()){i++;}
%>
//輸出內容
//輸出翻頁連接
合計:<%=currentPage%>/<%=intPageCount%><a href="List.jsp?page=1">第一頁</a><a

href="List.jsp?page=<%=upPage%>">上一頁</a>
<%
for(int j=1;j<=intPageCount;j++){
if(currentPage!=j){
%>
<a href="list.jsp?page=<%=j%>">[<%=j%>]</a>
<%
}else{
out.println(j);
}
}
%>
<a href="List.jsp?page=<%=nextPage%>">下一頁</a><a href="List.jsp?page=<%=intPageCount%>">最后頁

</a>
Xml方面
1、xml有哪些解析技術?區別是什么?
答:有DOM,SAX,STAX等
DOM:處理大型文件時其性能下降的非常厲害。這個問題是由DOM的樹結構所造成的,這種結構占用的內存較多,而且DOM必須在解析文件之前把整個文檔裝入內存,適合對XML的隨機訪問SAX:不現于DOM,SAX是事件驅動型的XML解析方式。它順序讀取XML文件,不需要一次全部裝載整個文件。當遇到像文件開頭,文檔結束,或者標簽開頭與標簽結束時,它會觸發一個事件,用戶通過在其回調事件中寫入處理代碼來處理XML文件,適合對XML的順序訪問
STAX:Streaming API for XML (StAX)
2、你在項目中用到了xml技術的哪些方面?如何實現的?
答:用到了數據存貯,信息配置兩方面。在做數據交換平臺時,將不能數據源的數據組裝成XML文件,然后將XML文件壓縮打包加密后通過網絡傳送給接收者,接收解密與解壓縮后再同XML文件中還原相關信息進行處理。在做軟件配置時,利用XML可以很方便的進行,軟件的各種配置參數都存貯在XML文件中。
3、用jdom解析xml文件時如何解決中文問題?如何解析?
答:看如下代碼,用編碼方式加以解決
package test;
import java.io.*;
public class DOMTest
{
** String inFile = "c:people.xml";
** String outFile = "c:people.xml";
public static void main(String args[])
{
new DOMTest();
}
public DOMTest()
{
try
{
javax.xml.parsers.DocumentBuilder builder =
javax.xml.parsers.DocumentBuilderFactory.newInstance().newDocumentBuilder();
org.w3c.dom.Document doc = builder.newDocument();
org.w3c.dom.Element root = doc.createElement("老師");
org.w3c.dom.Element wang = doc.createElement("王");
org.w3c.dom.Element liu = doc.createElement("劉");
wang.appendChild(doc.createTextNode("我是王老師"));
root.appendChild(wang);
doc.appendChild(root);
javax.xml.transform.Transformer transformer =
javax.xml.transform.TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(javax.xml.transform.OutputKeys.ENCODING, "gb2312");
transformer.setOutputProperty(javax.xml.transform.OutputKeys.INDENT, "yes");


transformer.transform(new javax.xml.transform.dom.DOMSource(doc),
new

javax.xml.transform.stream.StreamResult(outFile));
}
catch (Exception e)
{
System.out.println (e.getMessage());
}
}
}
4、編程用JAVA解析XML的方式.
答:用SAX方式解析XML,XML文件如下:
<?xml version="1.0" encoding="gb2312"?>
<person>
<name>王小明</name>
<college>信息學院</college>
<telephone>6258113</telephone>
<notes>男,1955年生,博士,95年調入海南大學</notes>
</person>
事件回調類SAXHandler.java
import java.io.*;
import java.util.Hashtable;
import org.xml.sax.*;
public class SAXHandler extends HandlerBase
{
** Hashtable table = new Hashtable();
** String currentElement = null;
** String currentValue = null;
public void setTable(Hashtable table)
{
this.table = table;
}
public Hashtable getTable()
{
return table;
}
public void startElement(String tag, AttributeList attrs)
throws SAXException
{
currentElement = tag;
}
public void characters(char[] ch, int start, int length)
throws SAXException
{
currentValue = new String(ch, start, length);
}
public void endElement(String name) throws SAXException
{
if (currentElement.equals(name))
table.put(currentElement, currentValue);
}
}
JSP內容顯示源碼,SaxXml.jsp:
<HTML>
<HEAD>
<TITLE>剖析XML文件people.xml</TITLE>
</HEAD>
<BODY>
<%@ page errorPage="ErrPage.jsp"
c %>
<%@ page import="java.io.*" %>
<%@ page import="java.util.Hashtable" %>
<%@ page import="org.w3c.dom.*" %>
<%@ page import="org.xml.sax.*" %>
<%@ page import="javax.xml.parsers.SAXParserFactory" %>
<%@ page import="javax.xml.parsers.SAXParser" %>
<%@ page import="SAXHandler" %>
<%
File file = new File("c:people.xml");
FileReader reader = new FileReader(file);
Parser parser;
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser();
SAXHandler handler = new SAXHandler();
sp.parse(new InputSource(reader), handler);
Hashtable hashTable = handler.getTable();
out.println("<TABLE BORDER=2><CAPTION>教師信息表</CAPTION>");
out.println("<TR><TD>姓名</TD>" + "<TD>" +
(String)hashTable.get(new String("name")) + "</TD></TR>");
out.println("<TR><TD>學院</TD>" + "<TD>" +
(String)hashTable.get(new String("college"))+"</TD></TR>");
out.println("<TR><TD>電話</TD>" + "<TD>" +
(String)hashTable.get(new String("telephone")) + "</TD></TR>");
out.println("<TR><TD>備注</TD>" + "<TD>" +
(String)hashTable.get(new String("notes")) + "</TD></TR>");
out.println("</TABLE>");
%>
</BODY>
</HTML>


liujg 2011-05-04 22:24 發表評論
]]>
(轉)讀HTTP協議(RFC-2616)總結http://m.tkk7.com/tbest/articles/321307.htmlliujgliujgTue, 18 May 2010 13:31:00 GMThttp://m.tkk7.com/tbest/articles/321307.htmlhttp://m.tkk7.com/tbest/comments/321307.htmlhttp://m.tkk7.com/tbest/articles/321307.html#Feedback0http://m.tkk7.com/tbest/comments/commentRss/321307.htmlhttp://m.tkk7.com/tbest/services/trackbacks/321307.html讀HTTP協議(RFC-2616)總結


http://ayufox.javaeye.com/blog/391812

關鍵字: http rest

1.資源(Resource)
      什么是資源,首先我們看《架構風格與基于網絡的軟件架構設計》的作者:Roy Thomas Fielding對資源的一個說明

Roy Thomas Fielding 寫道
REST對于信息的核心抽象是資源。任何能夠被命名的信息都能夠作為一個資源:一份文檔或一張圖片、一個暫時性的服務(例如,“洛杉磯今日的天氣”)、一個其他資源的集合、一個非虛擬的對象(例如,人)等等。換句話說,任何可能作為一個創作者的超文本引用的目標的概念都必須符合資源的定義。一個資源是到一組實體的概念上的映射,而不是在任何特定時刻與該映射相關聯的實體本身。
更精確地說,資源R是一個隨時間變化的成員函數MR(t),該函數將時間t映射到等價的一個實體或值的集合,集合中的值可能是資源的表現和/或資源的標識符。一個資源可以映射到空集,這允許在一個概念的任何實現存在之前引用這個概念——這一觀念對于Web之前的大多數超文本系統來說比較陌生 [61]。一些資源在它們被創建后的任何時刻來檢查,它們都對應著相同的值的集合,從這個意義上說它們是靜態的。其他的資源所對應的值則會隨時間而頻繁地變化。對于一個資源來說,唯一必須是靜態的是映射的語義,因為語義才是區別資源的關鍵。

       簡而言之,資源是一個抽象的東西,而在具體資源訪問時,會根據內容協商的結果表示成一個具體表述(Representations)。每個資源由統一的資源標識符(URI)來描述,類似于資源的ID,或者說資源的地址。
2.表述(Representations)
      表述是資源的具體表現形式,譬如,今天深圳的天氣(資源),可以使用一副天氣jpg圖來描述,也可以XML數據來描述,也可以使用HTML的頁面來描述,一種資源可以有多種表述,也就是說,通過同一個URI地址可以獲取到多種表現形式,而具體怎么表現,則取決于Web客戶端與Web服務端內容協商的一個結果。
3.內容協商
      客戶端和服務端通過內容協商來協商請求內容和響應內容的格式,主要協商的內容包括:
      請求協商:
      1)字符集(Accept-Charset):客戶端通過發送該協商建議服務端使用該字符集來發送響應結果,譬如
Accept-Charset=gb2312,utf-8;q=0.7,*;q=0.7,客戶端建議服務端優先使用gb2312或者utf-8來發送響應結果
      2)請求編碼(Accept-Encoding):客戶端告訴服務端客戶端所支持的編碼格式,譬如Accept-Encoding   =gzip,deflate表明客戶端支持gzip壓縮或者普通響應的結果
      3)語言(Accept-Language):客戶端通過發送該協商告訴服務端客戶端所使用的語言,譬如Accept-Language=zh-cn,zh;q=0.5表明客戶端偏號的語言是中文,譬如對于”今天深圳的天氣“這個資源來說,服務端可以通過該選項決定使用什么語言來表述資源
      4)表述偏好(Accept):客戶端通過該選項告訴服務端其表述的偏號,譬如一個請求”今天深圳的天氣“的Ajax程序,可以通過設置表述偏好為Accept=application/json來告訴服務端,希望得到Json描述的結果,而一個瀏覽器則可以通過傳輸表述偏好為Accept=text/html來告訴服務端,希望得到Html描述的結果
      響應協商:
      1)表述/表述字符集(Content-Type):服務端通過該協商告訴客戶端表述的格式和字符集的情況,譬如Content-Type=text/html; charset=utf-8表示響應內容格式為Html,字符集為utf-8
       2)表述編碼(Accept-Encoding):服務端通過該協商告訴客戶端表述的編碼,譬如Content-Encoding=gzip服務端告訴客戶端內容使用gzip壓縮
4.方法
     方法定義了對資源的操作,主要的方法包括GET、POST、UPDATE、DELETE等等,它們分別代表了對資源的讀、建、改、刪的操作
5.緩存
      HTTP協議支持在Web的各個節點對資源的表述進行緩存,譬如在瀏覽器客戶端、代理服務器、反向代理服務器、目標服務器等上對表述進行緩存(注意,此處的緩存不僅僅是指在目標服務器上進行的業務級別的緩存)
      1)客戶端請求
      如果客戶端緩存了某些表述,則在進行讀請求(GET)時,攜帶請求條件(所謂的條件GET,使用Cache-Control指令),服務端接收到客戶端的請求條件,比較確認客戶端的表述是否過時,如果沒有,則返回304響應,否則則把最新的表述響應給客戶端
      2)服務端響應
      服務端對一些需要緩存的表述,則響應中攜帶緩存指令,告訴請求客戶端如何對表述進行緩存
      3)方法對緩存的影響
      當對一個資源進行UPDATE或DELETE時,請求途經的所有服務器(如代理服務器、反向代理服務器、目標服務器)會自動將該資源對應的所有表述 緩存失效。
6.狀態碼
      狀態碼描述了資源請求的結果,主要狀態碼包括:
      1)1XX:信息類
      2)2XX:成功類
         典型的成功響應包括:
         200 OK,表示請求正常處理
         201 Created,表示POST請求已經接受,資源已創建,對于此響應,一般響應會攜帶新建資源的Reference給請求客戶端
         202 Accepted,表示POST/UDATE請求已經接受,但不一定處理,譬如對于POST/UPDATE請求為后臺新建線程處理,可以使用該響應碼
      3)3XX: 重定向類
         典型的重定向響應包括:
         300 Multiple Choice:表明請求的資源有多種表述
         301 Moved Permenently:表明所請求的資源已轉移到其他位置,建議到新的位置上去請求資源
         304 Not Modify:主要是針對攜帶條件的GET請求,服務端向客戶端表明所請求的資源沒有發生變化,可以繼續使用客戶端已緩存的數據
      4)4XX: 客戶端錯誤類
         典型的客戶端錯誤響應包括:
         400 Bad Request:表明客戶端的請求格式服務端無法識別
         403 Forbiden:客戶端要訪問的資源權限受限,不允許訪問
         404 Not found:客戶端要訪問的資源不存在
         405 Method Not Allowed:客戶端請求的方法不允許,譬如有可能一個資源不允許刪除,則不允許進行DELETE請求
         408 Request Timeout:請求超時
      5)5XX: 服務端錯誤類
         典型的服務端響應包括:
         500 Internal Server Error:服務器內部錯誤,無法響應
         503 Service Unavailable:服務器無法處理當前請求
         504 Gateway Timeout:網關超時





liujg 2010-05-18 21:31 發表評論
]]>
(轉) 用JAVA 實現“生產者-消費者”問題http://m.tkk7.com/tbest/articles/321107.htmlliujgliujgSun, 16 May 2010 11:03:00 GMThttp://m.tkk7.com/tbest/articles/321107.htmlhttp://m.tkk7.com/tbest/comments/321107.htmlhttp://m.tkk7.com/tbest/articles/321107.html#Feedback0http://m.tkk7.com/tbest/comments/commentRss/321107.htmlhttp://m.tkk7.com/tbest/services/trackbacks/321107.html生產者和消費者問題是從操作系統中的許多實際同步問題中抽象出來的具有
代表性的問題。它反映了操作系統中典型的同步例子。

  生產者進程(進程由多個線程組成)生產信息,例如它可以是計算進程。消費
者進程使用信息,它可以是輸出打印進程。由于生產者和消費者彼此獨立,且運
行速度不確定,所以很可能出現生產者已產生了信息而消費者卻沒有來得及接受
信息這種情況。為此,需要引入由一個或者若干個存儲單元組成的臨時存儲區,
以便存放生產者所產生的信息,平滑進程間由于速度不確定所帶來的問題。這個
臨時存儲區叫做緩沖區,通常用一維數組來表示。

  由一個或若干個存儲單元組成的緩沖區叫作“有窮緩沖區”。下面我們來分
析一下有窮緩沖的生產者和消費者的例子。

  假設有多個生產者和多個消費者,它們共享一個具有n個存儲單元的有窮緩沖
區Buffer(0……n-1),這是一個環形隊列。其隊尾指針Rear指向當前信息應存放
的位置(Buffer[Rear]),隊首指針Front指向當前取出信息的位置(Buffer[front
])。生產者進程總是把信息存放在Buffer[Rear]中,消費者進程則總是從Buffer
[Rear]中取出信息。如果想使生產者進程和消費者進程協調合作,則必須使它們
遵循如下規則:

  1) 只要緩沖區有存儲單元,生產者都可往其中存放信息;當緩沖區已滿時,
若任意生產者提出寫要求,則都必須等待;

  2) 只要緩沖區中有消息可取,消費者都可從緩沖區中取出消息;當緩沖區為
空時,若任意消費者想取出信息,則必須等待;

  3) 生產者們和消費者們不能同時讀、寫緩沖區。

  用JAVA 實現“生產者-消費者”問題的代碼如下:

public class ProducerConsumer {
 public static void main(String[] args) {
  SyncStack ss = new SyncStack();
  Producer p = new Producer(ss);
  Consumer c = new Consumer(ss);
  new Thread(p).start();
  new Thread(p).start();
  new Thread(p).start();
  new Thread(c).start();
 }
}

class WoTou {
 int id;
 WoTou(int id) {
  this.id = id;
 }
 public String toString() {
  return "WoTou : " + id;
 }
}

class SyncStack {
 int index = 0;
 WoTou[] arrWT = new WoTou[6];
 
 public synchronized void push(WoTou wt) {
  while(index == arrWT.length) {
   try {
    this.wait();
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
  }
  this.notifyAll(); 
  arrWT[index] = wt;
  index ++;
 }
 
 public synchronized WoTou pop() {
  while(index == 0) {
   try {
    this.wait();
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
  }
  this.notifyAll();
  index--;
  return arrWT[index];
 }
}

class Producer implements Runnable {
 SyncStack ss = null;
 Producer(SyncStack ss) {
  this.ss = ss;
 }
 
 public void run() {
  for(int i=0; i<20; i++) {
   WoTou wt = new WoTou(i);
   ss.push(wt);
System.out.println("生產了:" + wt);
   try {
    Thread.sleep((int)(Math.random() * 200));
   } catch (InterruptedException e) {
    e.printStackTrace();
   }  
  }
 }
}

class Consumer implements Runnable {
 SyncStack ss = null;
 Consumer(SyncStack ss) {
  this.ss = ss;
 }
 
 public void run() {
  for(int i=0; i<20; i++) {
   WoTou wt = ss.pop();
System.out.println("消費了: " + wt);
   try {
    Thread.sleep((int)(Math.random() * 1000));
   } catch (InterruptedException e) {
    e.printStackTrace();
   }  
  }
 }
}

生產者消費者問題是研究多線程程序時繞不開的問題,它的描述是有一塊生產者和消費者共享的有界緩沖區,生產者往緩沖區放入產品,消費者從緩沖區取走產品,這個過程可以無休止的執行,不能因緩沖區滿生產者放不進產品而終止,也不能因緩沖區空消費者無產品可取而終止。

       解決生產者消費者問題的方法有兩種,一種是采用某種機制保持生產者和消費者之間的同步,一種是在生產者和消費者之間建立一個管道。前一種有較高的效率并且可控制性較好,比較常用,后一種由于管道緩沖區不易控制及被傳輸數據對象不易封裝等原因,比較少用。
       同步問題的核心在于,CPU是按時間片輪詢的方式執行程序,我們無法知道某一個線程是否被執行、是否被搶占、是否結束等,因此生產者完全可能當緩沖區已滿的時候還在放入產品,消費者也完全可能當緩沖區為空時還在取出產品。
       現在同步問題的解決方法一般是采用信號或者加鎖機制,即生產者線程當緩沖區已滿時放棄自己的執行權,進入等待狀態,并通知消費者線程執行。消費者線程當緩沖區已空時放棄自己的執行權,進入等待狀態,并通知生產者線程執行。這樣一來就保持了線程的同步,并避免了線程間互相等待而進入死鎖狀態。
       JAVA語言提供了獨立于平臺的線程機制,保持了”write once, run anywhere”的特色。同時也提供了對同步機制的良好支持。
       在JAVA中,一共有四種方法支持同步,其中三個是同步方法,一個是管道方法。
1.       方法wait()/notify()
2.       方法await()/signal()
3.       阻塞隊列方法BlockingQueue
4.       管道方法PipedInputStream/PipedOutputStream
下面我們看各個方法的實現:
1.       方法wait()/notify()
wait()和notify()是根類Object的兩個方法,也就意味著所有的JAVA類都會具有這個兩個方法,為什么會被這樣設計呢?我們可以認為所有的對象默認都具有一個鎖,雖然我們看不到,也沒有辦法直接操作,但它是存在的。
wait()方法表示:當緩沖區已滿或空時,生產者或消費者線程停止自己的執行,放棄鎖,使自己處于等待狀態,讓另一個線程開始執行;
notify()方法表示:當生產者或消費者對緩沖區放入或取出一個產品時,向另一個線程發出可執行通知,同時放棄鎖,使自己處于等待狀態。
下面是一個例子代碼:
import java.util.LinkedList;

public class Sycn1...{
    private LinkedList<Object> myList =new LinkedList<Object>();
    private int MAX = 10;
   
    public Sycn1()...{
    }
   
    public void start()...{
            new Producer().start();
            new Consumer().start();
    }
   
    public static void main(String[] args) throws Exception...{
        Sycn1 s1 = new Sycn1();
        s1.start();
    }
   
    class Producer extends Thread...{       
        public void run()...{
            while(true)...{
                synchronized(myList)...{
                    try...{
                        while(myList.size() == MAX)...{
                            System.out.println("warning: it's full!");
                            myList.wait();
                        }
                        Object o = new Object();
                        if(myList.add(o))...{
                            System.out.println("Producer: " + o);
                            myList.notify();
                        }
                    }catch(InterruptedException ie)...{
                        System.out.println("producer is interrupted!");
                    }
                }
            }
        }
    }
   
    class Consumer extends Thread...{
        public void run()...{
            while(true)...{
                synchronized(myList)...{
                    try...{
                        while(myList.size() == 0)...{
                            System.out.println("warning: it's empty!");
                            myList.wait();
                        }
                        Object o = myList.removeLast();
                        System.out.println("Consumer: " + o);
                        myList.notify();
                    }catch(InterruptedException ie)...{
                        System.out.println("consumer is interrupted!");
                    }
                }
            }
        }
    }
   
}
2.       方法await()/signal()
在JDK5.0以后,JAVA提供了新的更加健壯的線程處理機制,包括了同步、鎖定、線程池等等,它們可以實現更小粒度上的控制。await()和signal()就是其中用來做同步的兩種方法,它們的功能基本上和wait()/notify()相同,完全可以取代它們,但是它們和新引入的鎖定機制Lock直接掛鉤,具有更大的靈活性。
下面是一個例子代碼:
import java.util.LinkedList;

import java.util.concurrent.locks.*;

public class Sycn2...{
    private LinkedList<Object> myList = new LinkedList<Object>();
    private int MAX = 10;
    private final Lock lock = new ReentrantLock();
    private final Condition full = lock.newCondition();
    private final Condition empty = lock.newCondition();
   
    public Sycn2()...{
    }
   
    public void start()...{
            new Producer().start();
            new Consumer().start();
    }
   
    public static void main(String[] args) throws Exception...{
        Sycn2 s2 = new Sycn2();
        s2.start();
    }
   
    class Producer extends Thread...{       
        public void run()...{
            while(true)...{
                lock.lock();
                try...{
                    while(myList.size() == MAX)...{
                        System.out.println("warning: it's full!");
                        full.await();
                    }
                    Object o = new Object();
                    if(myList.add(o))...{
                        System.out.println("Producer: " + o);
                        empty.signal();
                    }
                }catch(InterruptedException ie)...{
                    System.out.println("producer is interrupted!");
                }finally...{
                    lock.unlock();
                }
            }
        }
    }
   
    class Consumer extends Thread...{
        public void run()...{
            while(true)...{
                lock.lock();
                try...{
                    while(myList.size() == 0)...{
                        System.out.println("warning: it's empty!");
                        empty.await();
                    }
                    Object o = myList.removeLast();
                    System.out.println("Consumer: " + o);
                    full.signal();
                }catch(InterruptedException ie)...{
                    System.out.println("consumer is interrupted!");
                }finally...{
                    lock.unlock();
                }
            }
        }
    }
   
}
3.       阻塞隊列方法BlockingQueue
BlockingQueue也是JDK5.0的一部分,它是一個已經在內部實現了同步的隊列,實現方式采用的是我們的第2種await()/signal()方法。它可以在生成對象時指定容量大小。
它用于阻塞操作的是put()和take()方法。
put()方法類似于我們上面的生產者線程,容量最大時,自動阻塞。
take()方法類似于我們上面的消費者線程,容量為0時,自動阻塞。
下面是一個例子代碼:
import java.util.concurrent.*;

public class Sycn3...{
    private LinkedBlockingQueue<Object> queue = new LinkedBlockingQueue<Object>(10);
    private int MAX = 10;
   
    public Sycn3()...{
    }
   
    public void start()...{
            new Producer().start();
            new Consumer().start();
    }
   
    public static void main(String[] args) throws Exception...{
        Sycn3 s3 = new Sycn3();
        s3.start();
    }
   
    class Producer extends Thread...{       
        public void run()...{
            while(true)...{
                //synchronized(this){
                try...{
                    if(queue.size() == MAX)
                        System.out.println("warning: it's full!");
                    Object o = new Object();
                    queue.put(o);
                    System.out.println("Producer: " + o);
                    }catch(InterruptedException e)...{
                        System.out.println("producer is interrupted!");
                    }
                //}
            }
        }
    }
   
    class Consumer extends Thread...{
        public void run()...{
            while(true)...{
                //synchronized(this){
                try...{
                    if(queue.size() == 0)
                        System.out.println("warning: it's empty!");
                    Object o = queue.take();
                    System.out.println("Consumer: " + o);
                    }catch(InterruptedException e)...{
                        System.out.println("producer is interrupted!");
                    }
                //}
            }
        }
    }
   
}
你發現這個例子中的問題了嗎?
如果沒有,我建議你運行一下這段代碼,仔細觀察它的輸出,是不是有下面這個樣子的?為什么會這樣呢?

warning: it's full!
Producer: java.lang.object@4526e2a

你可能會說這是因為put()和System.out.println()之間沒有同步造成的,我也這樣認為,我也這樣認為,但是你把run()中的synchronized前面的注釋去掉,重新編譯運行,有改觀嗎?沒有。為什么?
這是因為,當緩沖區已滿,生產者在put()操作時,put()內部調用了await()方法,放棄了線程的執行,然后消費者線程執行,調用take()方法,take()內部調用了signal()方法,通知生產者線程可以執行,致使在消費者的println()還沒運行的情況下生產者的println()先被執行,所以有了上面的輸出。run()中的synchronized其實并沒有起什么作用。
對于BlockingQueue大家可以放心使用,這可不是它的問題,只是在它和別的對象之間的同步有問題。
對于這種多重嵌套同步的問題,以后再談吧,歡迎大家討論??!
4.       管道方法PipedInputStream/PipedOutputStream
這個類位于java.io包中,是解決同步問題的最簡單的辦法,一個線程將數據寫入管道,另一個線程從管道讀取數據,這樣便構成了一種生產者/消費者的緩沖區編程模式。
下面是一個例子代碼,在這個代碼我沒有使用Object對象,而是簡單的讀寫字節值,這是因為PipedInputStream/PipedOutputStream不允許傳輸對象,這是JAVA本身的一個bug,具體的大家可以看sun的解釋:http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4131126
import java.io.*;

public class Sycn4...{
    private PipedOutputStream pos;
    private PipedInputStream pis;
    //private ObjectOutputStream oos;
    //private ObjectInputStream ois;
   
    public Sycn4()...{
        try...{
            pos = new PipedOutputStream();
            pis = new PipedInputStream(pos);
            //oos = new ObjectOutputStream(pos);
            //ois = new ObjectInputStream(pis);
        }catch(IOException e)...{
            System.out.println(e);
        }
    }
   
    public void start()...{
        new Producer().start();
        new Consumer().start();
    }
   
    public static void main(String[] args) throws Exception...{
        Sycn4 s4 = new Sycn4();
        s4.start();
    }
   
    class Producer extends Thread...{
        public void run() ...{
            try...{
                while(true)...{
                    int b = (int) (Math.random() * 255);
                    System.out.println("Producer: a byte, the value is " + b);
                    pos.write(b);
                    pos.flush();
                    //Object o = new MyObject();
                    //oos.writeObject(o);
                    //oos.flush();
                    //System.out.println("Producer: " + o);
                }
            }catch(Exception e)...{
                //System.out.println(e);
                e.printStackTrace();
            }finally...{
                try...{
                    pos.close();
                    pis.close();
                    //oos.close();
                    //ois.close();
                }catch(IOException e)...{
                    System.out.println(e);
                }
            }
        }
    }
   
    class Consumer extends Thread...{
        public void run()...{
            try...{
                while(true)...{
                    int b = pis.read();
                    System.out.println("Consumer: a byte, the value is " + String.valueOf(b));
                    //Object o = ois.readObject();
                    //if(o != null)
                        //System.out.println("Consumer: " + o);
                }
            }catch(Exception e)...{
                //System.out.println(e);
                e.printStackTrace();
            }finally...{
                try...{
                    pos.close();
                    pis.close();
                    //oos.close();
                    //ois.close();
                }catch(IOException e)...{
                    System.out.println(e);
                }
            }
        }
    }
   
    //class MyObject implements Serializable {
    //}
}

出處:http://blog.csdn.net/JaunLee/archive/2008/02/01/2077291.aspx



liujg 2010-05-16 19:03 發表評論
]]>
<轉>絕對路徑相對路徑http://m.tkk7.com/tbest/articles/317902.htmlliujgliujgFri, 09 Apr 2010 16:04:00 GMThttp://m.tkk7.com/tbest/articles/317902.htmlhttp://m.tkk7.com/tbest/comments/317902.htmlhttp://m.tkk7.com/tbest/articles/317902.html#Feedback0http://m.tkk7.com/tbest/comments/commentRss/317902.htmlhttp://m.tkk7.com/tbest/services/trackbacks/317902.html
  絕對路徑:絕對路徑就是你的主頁上的文件或目錄在硬盤上真正的路徑,(URL和物理路徑)例如:
C:\xyz\test.txt 代表了test.txt文件的絕對路徑。http://www.sun.com/index.htm也代表了一個
URL絕對路徑。

  相對路徑:相對與某個基準目錄的路徑。包含Web的相對路徑(HTML中的相對目錄),例如:在
Servlet中,"/"代表Web應用的跟目錄。和物理路徑的相對表示。例如:"./" 代表當前目錄,
"../"代表上級目錄。這種類似的表示,也是屬于相對路徑。

另外關于URI,URL,URN等內容,請參考RFC相關文檔標準。

RFC 2396: Uniform Resource Identifiers (URI): Generic Syntax,
(http://www.ietf.org/rfc/rfc2396.txt)


2.關于JSP/Servlet中的相對路徑和絕對路徑。

2.1服務器端的地址

   服務器端的相對地址指的是相對于你的web應用的地址,這個地址是在服務器端解析的
(不同于html和javascript中的相對地址,他們是由客戶端瀏覽器解析的)也就是說這時候
在jsp和servlet中的相對地址應該是相對于你的web應用,即相對于http://192.168.0.1/webapp/的。

  其用到的地方有:
forward:servlet中的request.getRequestDispatcher(address);這個address是
在服務器端解析的,所以,你要forward到a.jsp應該這么寫:
request.getRequestDispatcher(“/user/a.jsp”)這個/相對于當前的web應用webapp,
其絕對地址就是:http://192.168.0.1/webapp/user/a.jsp。
sendRedirect:在jsp中<%response.sendRedirect("/rtccp/user/a.jsp");%>

2.22、客戶端的地址

       所有的html頁面中的相對地址都是相對于服務器根目錄(http://192.168.0.1/)的,
而不是(跟目錄下的該Web應用的目錄)http://192.168.0.1/webapp/的。
Html中的form表單的action屬性的地址應該是相對于服務器根目錄(http://192.168.0.1/)的,
所以,如果提交到a.jsp為:action="/webapp/user/a.jsp"或action="<%=request.getContextPath()%>"/user/a.jsp;
  提交到servlet為actiom="/webapp/handleservlet" 
  Javascript也是在客戶端解析的,所以其相對路徑和form表單一樣。


  因此,一般情況下,在JSP/HTML頁面等引用的CSS,Javascript.Action等屬性前面最好都加上
<%=request.getContextPath()%>,以確保所引用的文件都屬于Web應用中的目錄。
另外,應該盡量避免使用類似".","./","../../"等類似的相對該文件位置的相對路徑,這樣
當文件移動時,很容易出問題。


3. JSP/Servlet中獲得當前應用的相對路徑和絕對路徑
3.1 JSP中獲得當前應用的相對路徑和絕對路徑
根目錄所對應的絕對路徑:request.getRequestURI()
文件的絕對路徑     :application.getRealPath(request.getRequestURI());
當前web應用的絕對路徑 :application.getRealPath("/");
取得請求文件的上層目錄:new File(application.getRealPath(request.getRequestURI())).getParent()

3.2 Servlet中獲得當前應用的相對路徑和絕對路徑
根目錄所對應的絕對路徑:request.getServletPath();
文件的絕對路徑    :request.getSession().getServletContext().getRealPath
(request.getRequestURI())  
當前web應用的絕對路徑 :servletConfig.getServletContext().getRealPath("/");
     (ServletContext對象獲得幾種方式:
       javax.servlet.http.HttpSession.getServletContext()
       javax.servlet.jsp.PageContext.getServletContext()
       javax.servlet.ServletConfig.getServletContext()
     )

4.java 的Class中獲得相對路徑,絕對路徑的方法
4.1單獨的Java類中獲得絕對路徑
  根據java.io.File的Doc文擋,可知:
默認情況下new File("/")代表的目錄為:System.getProperty("user.dir")。
一下程序獲得執行類的當前路徑
package org.cheng.file;
import java.io.File;

public class FileTest {
    public static void main(String[] args) throws Exception {     

  System.out.println(Thread.currentThread().getContextClassLoader().getResource(""));    

  System.out.println(FileTest.class.getClassLoader().getResource(""));       

  System.out.println(ClassLoader.getSystemResource(""));       
  System.out.println(FileTest.class.getResource(""));       
  System.out.println(FileTest.class.getResource("/")); //Class文件所在路徑 
  System.out.println(new File("/").getAbsolutePath());       
  System.out.println(System.getProperty("user.dir"));   
}
}

4.2服務器中的Java類獲得當前路徑(來自網絡)
(1).Weblogic

WebApplication的系統文件根目錄是你的weblogic安裝所在根目錄。
例如:如果你的weblogic安裝在c:\bea\weblogic700.....
那么,你的文件根路徑就是c:\.
所以,有兩種方式能夠讓你訪問你的服務器端的文件:
a.使用絕對路徑:
比如將你的參數文件放在c:\yourconfig\yourconf.properties,
直接使用 new FileInputStream("yourconfig/yourconf.properties");
b.使用相對路徑:
相對路徑的根目錄就是你的webapplication的根路徑,即WEB-INF的上一級目錄,將你的參數文件放

在yourwebapp\yourconfig\yourconf.properties,
這樣使用:
new FileInputStream("./yourconfig/yourconf.properties");
這兩種方式均可,自己選擇。

(2).Tomcat

在類中輸出System.getProperty("user.dir");顯示的是%Tomcat_Home%/bin

(3).Resin

不是你的JSP放的相對路徑,是JSP引擎執行這個JSP編譯成SERVLET
的路徑為根.比如用新建文件法測試File f = new File("a.htm");
這個a.htm在resin的安裝目錄下

(4).如何讀相對路徑哪?

在Java文件中getResource或getResourceAsStream均可

例:getClass().getResourceAsStream(filePath);//filePath可以是"/filename",這里的/代表web

發布根路徑下WEB-INF/classes

默認使用該方法的路徑是:WEB-INF/classes。已經在Tomcat中測試。

5.讀取文件時的相對路徑,避免硬編碼和絕對路徑的使用。(來自網絡)
5.1 采用Spring的DI機制獲得文件,避免硬編碼。
   參考下面的連接內容:
   http://www.javajia.net/viewtopic.php?p=90213&
5.2 配置文件的讀取
參考下面的連接內容:
http://dev.csdn.net/develop/article/39/39681.shtm
5.3 通過虛擬路徑或相對路徑讀取一個xml文件,避免硬編碼
參考下面的連接內容:
http://club.gamvan.com/club/clubPage.jsp?iPage=1&tID=10708&ccID=8

6.Java中文件的常用操作(復制,移動,刪除,創建等)(來自網絡)
常用 java File 操作類
http://www.easydone.cn/014/200604022353065155.htm

Java文件操作大全(JSP中)
http://www.pconline.com.cn/pcedu/empolder/gj/java/0502/559401.html

java文件操作詳解(Java中文網)
http://www.51cto.com/html/2005/1108/10947.htm

JAVA 如何創建\刪除\修改\復制目錄及文件
http://www.gamvan.com/developer/java/2005/2/264.html

總結:
通過上面內容的使用,可以解決在Web應用服務器端,移動文件,查找文件,復制
刪除文件等操作,同時對服務器的相對地址,絕對地址概念更加清晰。
建議參考URI,的RFC標準文擋。同時對Java.io.File. Java.net.URI.等內容了解透徹
對其他方面的理解可以更加深入和透徹。
==================================================================================

參考資料:
java/docs/

java.io.File
java.io.InputStream
java.io.OutputStream
java.io.FileInputStream
java.io.FileReader;
java.io.FileOutputStream
java.io.FileWriter;
java.net.URI
java.net.URL


絕對路徑與相對路徑祥解
http://www.webjx.com/htmldata/2005-02-26/1109430310.html

[『J道習練』]JSP和Servlet中的絕對路徑和相對路徑
http://w3china.org/blog/more.asp?name=pcthomas&id=9122&commentid=12376

JSP,Servlet,Class獲得當前應用的相對路徑和絕對路徑
http://cy.lzu.edu.cn/cy/club/clubPage.jsp?ccStyle=0&tID=886&ccID=77

如何獲得當前文件路徑
http://www.matrix.org.cn/resource/article/44/44113_java.html

通過Spring注入機制,取得文件
http://www.javajia.net/viewtopic.php?p=90213&

配置文件的讀取
http://dev.csdn.net/develop/article/39/39681.shtm

讀取配置文件,通過虛擬路徑或相對路徑讀取一個xml文件,避免硬編碼!
http://club.gamvan.com/club/clubPage.jsp?iPage=1&tID=10708&ccID=8

常用 java File 操作類
http://www.easydone.cn/014/200604022353065155.htm

Java文件操作大全
http://www.pconline.com.cn/pcedu/empolder/gj/java/0502/559401.html

Java文件操作詳解
http://www.51cto.com/html/2005/1108/10947.htm
原文地址:http://m.tkk7.com/meil/archive/2006/10/10/73908.html

liujg 2010-04-10 00:04 發表評論
]]>
JVM內存模型(轉)http://m.tkk7.com/tbest/articles/288762.htmlliujgliujgTue, 28 Jul 2009 08:14:00 GMThttp://m.tkk7.com/tbest/articles/288762.htmlhttp://m.tkk7.com/tbest/comments/288762.htmlhttp://m.tkk7.com/tbest/articles/288762.html#Feedback0http://m.tkk7.com/tbest/comments/commentRss/288762.htmlhttp://m.tkk7.com/tbest/services/trackbacks/288762.html

原文地址:http://tech.e800.com.cn/articles/2009/79/1247104593971_1.html
JVM內存由 Perm 和 Heap 組成. 其中
Heap = {Old + NEW = { Eden , from, to } }
JVM內存模型中分兩大塊,一塊是 NEW Generation, 另一塊是Old Generation. 在New Generation中,有一個叫Eden的空間,主要是用來存放新生的對象,還有兩個Survivor Spaces(from,to), 它們用來存放每次垃圾回收后存活下來的對象。在Old Generation中,主要存放應用程序中生命周期長的內存對象,還有個Permanent Generation,主要用來放JVM自己的反射對象,比如類對象和方法對象等。

垃圾回收描述:

在New Generation塊中,垃圾回收一般用Copying的算法,速度快。每次GC的時候,存活下來的對象首先由Eden拷貝到某個Survivor Space, 當Survivor Space空間滿了后, 剩下的live對象就被直接拷貝到Old Generation中去。因此,每次GC后,Eden內存塊會被清空。在Old Generation塊中,垃圾回收一般用mark-compact的算法,速度慢些,但減少內存要求.
垃圾回收分多級,0級為全部(Full)的垃圾回收,會回收OLD段中的垃圾;1級或以上為部分垃圾回收,只會回收NEW中的垃圾,內存溢出通常發生于OLD段或Perm段垃圾回收后,仍然無內存空間容納新的Java對象的情況。

當一個URL被訪問時,內存申請過程如下:
A. JVM會試圖為相關Java對象在Eden中初始化一塊內存區域
B. 當Eden空間足夠時,內存申請結束。否則到下一步
C. JVM試圖釋放在Eden中所有不活躍的對象(這屬于1或更高級的垃圾回收), 釋放后若Eden空間仍然不足以放入新對象,則試圖將部分Eden中活躍對象放入Survivor區
D. Survivor區被用來作為Eden及OLD的中間交換區域,當OLD區空間足夠時,Survivor區的對象會被移到Old區,否則會被保留在Survivor區
E. 當OLD區空間不夠時,JVM會在OLD區進行完全的垃圾收集(0級)
F. 完全垃圾收集后,若Survivor及OLD區仍然無法存放從Eden復制過來的部分對象,導致JVM無法在Eden區為新對象創建內存區域,則出現”out of memory錯誤”

JVM調優建議:

ms/mx:定義YOUNG+OLD段的總尺寸,ms為JVM啟動時YOUNG+OLD的內存大??;mx為最大可占用的YOUNG+OLD內存大小。在用戶生產環境上一般將這兩個值設為相同,以減少運行期間系統在內存申請上所花的開銷。
NewSize/MaxNewSize:定義YOUNG段的尺寸,NewSize為JVM啟動時YOUNG的內存大??;MaxNewSize為最大可占用的YOUNG內存大小。在用戶生產環境上一般將這兩個值設為相同,以減少運行期間系統在內存申請上所花的開銷。
PermSize/MaxPermSize:定義Perm段的尺寸,PermSize為JVM啟動時Perm的內存大?。籑axPermSize為最大可占用的Perm內存大小。在用戶生產環境上一般將這兩個值設為相同,以減少運行期間系統在內存申請上所花的開銷。
SurvivorRatio:設置Survivor空間和Eden空間的比例

內存溢出的可能性

1. OLD段溢出
這種內存溢出是最常見的情況之一,產生的原因可能是:
1) 設置的內存參數過小(ms/mx, NewSize/MaxNewSize)
2) 程序問題
單個程序持續進行消耗內存的處理,如循環幾千次的字符串處理,對字符串處理應建議使用StringBuffer。此時不會報內存溢出錯,卻會使系統持續垃圾收集,無法處理其它請求,相關問題程序可通過Thread Dump獲?。ㄒ娤到y問題診斷一章)單個程序所申請內存過大,有的程序會申請幾十乃至幾百兆內存,此時JVM也會因無法申請到資源而出現內存溢出,對此首先要找到相關功能,然后交予程序員修改,要找到相關程序,必須在Apache日志中尋找。
當Java對象使用完畢后,其所引用的對象卻沒有銷毀,使得JVM認為他還是活躍的對象而不進行回收,這樣累計占用了大量內存而無法釋放。由于目前市面上還沒有對系統影響小的內存分析工具,故此時只能和程序員一起定位。

2. Perm段溢出
通常由于Perm段裝載了大量的Servlet類而導致溢出,目前的解決辦法:
1) 將PermSize擴大,一般256M能夠滿足要求
2) 若別無選擇,則只能將servlet的路徑加到CLASSPATH中,但一般不建議這么處理

3. C Heap溢出
系統對C Heap沒有限制,故C Heap發生問題時,Java進程所占內存會持續增長,直到占用所有可用系統內存

其他:

JVM有2個GC線程。第一個線程負責回收Heap的Young區。第二個線程在Heap不足時,遍歷Heap,將Young 區升級為Older區。Older區的大小等于-Xmx減去-Xmn,不能將-Xms的值設的過大,因為第二個線程被迫運行會降低JVM的性能。
為什么一些程序頻繁發生GC?有如下原因:
l 程序內調用了System.gc()或Runtime.gc()。
l 一些中間件軟件調用自己的GC方法,此時需要設置參數禁止這些GC。
l Java的Heap太小,一般默認的Heap值都很小。
l 頻繁實例化對象,Release對象。此時盡量保存并重用對象,例如使用StringBuffer()和String()。
如果你發現每次GC后,Heap的剩余空間會是總空間的50%,這表示你的Heap處于健康狀態。許多Server端的Java程序每次GC后最好能有65%的剩余空間。
經驗之談:
1.Server端JVM最好將-Xms和-Xmx設為相同值。為了優化GC,最好讓-Xmn值約等于-Xmx的1/3[2]。
2.一個GUI程序最好是每10到20秒間運行一次GC,每次在半秒之內完成[2]。
注意:
1.增加Heap的大小雖然會降低GC的頻率,但也增加了每次GC的時間。并且GC運行時,所有的用戶線程將暫停,也就是GC期間,Java應用程序不做任何工作。
2.Heap大小并不決定進程的內存使用量。進程的內存使用量要大于-Xmx定義的值,因為Java為其他任務分配內存,例如每個線程的Stack等。
2.Stack的設定
每個線程都有他自己的Stack。

-Xss

每個線程的Stack大小
Stack的大小限制著線程的數量。如果Stack過大就好導致內存溢漏。-Xss參數決定Stack大小,例如-Xss1024K。如果Stack太小,也會導致Stack溢漏。
3.硬件環境
硬件環境也影響GC的效率,例如機器的種類,內存,swap空間,和CPU的數量。
如果你的程序需要頻繁創建很多transient對象,會導致JVM頻繁GC。這種情況你可以增加機器的內存,來減少Swap空間的使用[2]。
4.4種GC
第一種為單線程GC,也是默認的GC。,該GC適用于單CPU機器。
第二種為Throughput GC,是多線程的GC,適用于多CPU,使用大量線程的程序。第二種GC與第一種GC相似,不同在于GC在收集Young區是多線程的,但在Old區和第一種一樣,仍然采用單線程。-XX:+UseParallelGC參數啟動該GC。
第三種為Concurrent Low Pause GC,類似于第一種,適用于多CPU,并要求縮短因GC造成程序停滯的時間。這種GC可以在Old區的回收同時,運行應用程序。-XX:+UseConcMarkSweepGC參數啟動該GC。

第四種為Incremental Low Pause GC,適用于要求縮短因GC造成程序停滯的時間。這種GC可以在Young區回收的同時,回收一部分Old區對象。-Xincgc參數啟動該GC。



liujg 2009-07-28 16:14 發表評論
]]>
轉:用Java Socket開發小型服務器,支持上千個并發(上)http://m.tkk7.com/tbest/articles/249721.htmlliujgliujgSun, 04 Jan 2009 04:55:00 GMThttp://m.tkk7.com/tbest/articles/249721.htmlhttp://m.tkk7.com/tbest/comments/249721.htmlhttp://m.tkk7.com/tbest/articles/249721.html#Feedback0http://m.tkk7.com/tbest/comments/commentRss/249721.htmlhttp://m.tkk7.com/tbest/services/trackbacks/249721.html 
Java Socket
套接字(socket)為兩臺計算機之間的通信提供了一種機制,在James Gosling注意到Java 語言之前,套接字就早已赫赫有名。該語言只是讓您不必了解底層操作系統的細節就能有效地使用套接字。
1 客戶機/服務器模型
在飯店里,菜單上各種具有異國情調的食品映入你的眼簾,于是你要了一份pizza。幾分鐘后,你用力咀嚼澆著融化的乳酪和其他你喜歡的配料的熱pizza。你不知道,也不想知道:侍者從那里弄來了pizza,在制作過程中加進了什么,以及配料是如何獲得的。
上例中包含的實體有:美味的pizza、接受你定餐的侍者、制作pizza的廚房,當然還有你。你是定pizza的顧客或客戶。制作pizza的過程對于你而言是被封裝的。你的請求在廚房中被處理,pizza制作完成后,由侍者端給你。
你所看到的就是一個客戶機/服務器模型??蛻魴C向服務器發送一個請求或命令。服務器處理客戶機的請求??蛻魴C和服務器之間的通訊是客戶機/服務器模型中的一個重要組成部分,通常通過網絡進行。
客戶機/服務器模型是一個應用程序開發框架,該框架是為了將數據的表示與其內部的處理和存儲分離開來而設計的。客戶機請求服務,服務器為這些請求服務。請求通過網絡從客戶機傳遞到服務器。服務器所進行的處理對客戶機而言是隱藏的。一個服務器可以為多臺客戶機服務。
多臺客戶機訪問服務器
服務器和客戶機不一定是硬件組件。它們可以是工作啊同一機器或不同機器上的程序。、
考慮一個航空定票系統中的數據輸入程序:數據----乘客名、航班號、飛行日期、目的地等可以被輸入到前端----客戶機的應用程序中。一旦數據輸入之后,客戶機將數據發送到后端----服務器端。服務器處理數據并在數據庫中保存數據??蛻魴C/服務器模型的重要性在于所有的數據都存放在同一地點。客戶機從不同的地方訪問同一數據源,服務器對所有的輸入數據應用同樣的檢驗規則。
萬維網為‘為什么要將數據的表示與其存儲、處理分離開來’提供了一個很好的例子。在Web上,你無需控制最終用戶用來訪問你數據的平臺和軟件。你可以考慮編寫出適用與每一種潛在的目標平臺的應用程序。
‘客戶機/服務器應用程序的服務器部分’管理通過多個客戶機訪問服務器的、多個用戶共享的資源。表明‘客戶機/服務器程序的服務器部分’強大功能的最好例子應該是Web服務器,它通過Internet將HTML頁傳遞給不同的Web用戶。
Java編程語言中最基本的特點是在Java中創建的程序的代碼的可移植性。因為具有其他語言所不具備的代碼可移植性,Java允許用戶只要編寫一次應用程序,就可以在任何客戶機系統上發布它,并可以讓客戶機系統解釋該程序。這意味著:你只要寫一次代碼,就能使其在任何平臺上運行。

2 協議
當你同朋友交談時,你們遵循一些暗含的規則(或協議)。例如:你們倆不能同時開始說話,或連續不間斷地說話。如果你們這樣作的話,誰也不能理解對方所說的東西。當你說話時,你的朋友傾聽,反之亦然。你們以雙方都能理解的語言和速度進行對話。
當計算機之間進行通訊的時候,也需要遵循一定的規則。數據以包的形式從一臺機器發送到另一臺。這些規則管理數據打包、數據傳輸速度和重新 數據將其恢復成原始形式。這些規則被稱為網絡協議。網絡協議是通過網絡進行通訊的系統所遵循的一系列規則和慣例。連網軟件通常實現有高低層次之分的多層協議。網絡協議的例子有:TCP/IP、UDP、Apple Talk和NetBEUI。
Java提供了一個豐富的、支持網絡的類庫,這些類使得應用程序能方便地訪問網絡資源。Java提供了兩種通訊工具。它們是:使用用戶報文協議(UDP)的報文和使用傳輸控制協議/因特網協議(TCP/IP)的Sockets(套接字)。
數據報包是一個字節數組從一個程序(發送程序)傳送到另一個(接受程序)。由于數據報遵守UDP,不保證發出的數據包必須到達目的地。數據報并不是可信賴的。因此,僅當傳送少量數據時才使用,而且發送者和接受者之間的距離間隔不大,假如是網絡交通高峰,或接受程序正處理來自其他程序的多個請求,就有機會出現數據報包的丟失。
Sockets套接字用TCP來進行通訊。套接字模型同其他模型相比,優越性在于其不受客戶請求來自何處的影響。只要客戶機遵循TCP/IP協議,服務器就會對它的請求提供服務。這意味著客戶機可以是任何類型的計算機??蛻魴C不再局限為UNIX、Windows、DOS或Macintosh平臺,因此,網上所有遵循TCP/IP協議的計算機可以通過套接字互相通訊。

3 Sockets套接字
3.1 Sockets概況
在客戶機/服務器應用程序中,服務器提供象處理數據庫查詢或修改數據庫中的數據之類的服務。發生在客戶機和服務器之間的通訊必須是可靠的,同時數據在客戶機上的次序應該和服務器發送出來的次序相同。
什么是套接字?
既然我們已經知道套接字扮演的角色,那么剩下的問題是:什么是套接字?Bruce Eckel 在他的《Java 編程思想》一書中這樣描述套接字:套接字是一種軟件抽象,用于表達兩臺機器之間的連接“終端”。對于一個給定的連接,每臺機器上都有一個套接字,您也可以想象它們之間有一條虛擬的“電纜”,“電纜”的每一端都插入到套接字中。當然,機器之間的物理硬件和電纜連接都是完全未知的。抽象的全部目的是使我們無須知道不必知道的細節。
簡言之,一臺機器上的套接字與另一臺機器上的套接字交談就創建一條通信通道。程序員可以用該通道來在兩臺機器之間發送數據。當您發送數據時,TCP/IP 協議棧的每一層都會添加適當的報頭信息來包裝數據。這些報頭幫助協議棧把您的數據送到目的地。好消息是 Java 語言通過"流"為您的代碼提供數據,從而隱藏了所有這些細節,這也是為什么它們有時候被叫做流套接字(streaming socket)的原因。
把套接字想成兩端電話上的聽筒,我和您通過專用通道在我們的電話聽筒上講話和聆聽。直到我們決定掛斷電話,對話才會結束(除非我們在使用蜂窩電話)。而且我們各自的電話線路都占線,直到我們掛斷電話。
如果想在沒有更高級機制如 ORB(以及 CORBA、RMI、IIOP 等等)開銷的情況下進行兩臺計算機之間的通信,那么套接字就適合您。套接字的低級細節相當棘手。幸運的是,Java 平臺給了您一些雖然簡單但卻強大的更高級抽象,使您可以容易地創建和使用套接字。
傳輸控制協議(TCP)提供了一條可靠的、點對點的通訊通道,客戶機/服務器應用程序可以用該通道互相通訊。要通過TCP進行通訊,客戶機和服務器程序建立連接并綁定套接字。套接字用于處理通過網絡連接的應用程序之間的通訊。客戶機和服務器之間更深入的通訊通過套接字完成。
Java被設計成一種連網語言。它通過將連接功能封裝到套接字類里而使得網絡編程更加容易。套接字類即Socket類(它創建一個客戶套接字)和ServerSocket類(它創建一個服務器套接字)。套接字類大致介紹如下:
l     Socket是基類,它支持TCP協議。TCP是一個可靠的流網絡連接協議。Socket類提供了流輸入/輸出的方法,使得從套接字中讀出數據和往套接字中寫數據都很容易。該類對于編寫因特網上的通訊程序而言是必不可少的。
l     ServerSocket是一個因特網服務程序用來監聽客戶請求的類。ServerSocket實際上并不執行服務;而是創建了一個Socket對象來代表客戶機。通訊由創建的對象來完成。
3.2 IP地址和端口
因特網服務器可以被認為是一組套接字類,它們提供了一般稱為服務的附加功能。服務的例子有:電子郵件、遠程登錄的Telnet、和通過網絡傳輸文件的文件傳輸協議(FTP)。每種服務都與一個端口相聯系。端口是一個數值地址,通過它來處理服務請求(就象請求Web頁一樣)。
TCP協議需要兩個數據項:IP地址和端口號。因此,當鍵入http://www.jinnuo.com時,你是如何進入金諾的主頁呢?
因特網協議(IP)提供每一項網絡設備。這些設備都帶有一個稱為IP地址的邏輯地址。由因特網協議提供的IP地址具有特定的形式。每個IP地址都是32位的數值,表示4個范圍在0到255之間的8位數值金諾已經注冊了它的名字,分配給http://www.jinnuo.com的IP地址為192.168.0.110。
注意:域名服務或DNS服務是將http://www.jinnuo.com翻譯成192.168.0.110的服務。這使你可以鍵入http://www.jinnuo.com而不必記住IP地址。想象一下,怎么可能記住所有需要訪問的站點的IP地址!有趣的是一個網絡名可以映射到許多IP地址。對于經常訪問的站點可能需要這一功能,因為這些站點容納大量的信息,并需要多個IP地址來提供業務服務。例如:192.168.0.110的實際的內部名稱為http://www.jinnuo.com。DNS可以將分配給jinnuo Ltd.的一系列IP地址翻譯成http://www.jinnuo.com。
如果沒有指明端口號,則使用服務文件中服務器的端口。每種協議有一個缺省的端口號,在端口號未指明時使用該缺省端口號。
端口號     應用
21     FTP.傳輸文件
23     Telnet.提供遠程登錄
25     SMTP.傳遞郵件信息
67     BOOTP.在啟動時提供配置情況
80     HTTP.傳輸Web頁
109     POP.使用戶能訪問遠程系統中的郵箱
讓我們再來看一下URL:http://www.jinnuo.com
URL的第一部分(http)意味著你正在使用超文本傳輸協議(HTTP),該協議處理Web文檔。如果沒有指明文件,大多數的Web服務器會取一個叫index.html文件。因此,IP地址和端口既可以通過明確指出URL各部分來決定,也可以由缺省值決定。
4 創建Socket客戶
我們將在本部分討論的示例將闡明在 Java 代碼中如何使用 Socket 和 ServerSocket。客戶機用 Socket 連接到服務器。服務器用 ServerSocket 在端口 1001 偵聽??蛻魴C請求服務器 C: 驅動器上的文件內容。
創建 RemoteFileClient 類
import java.io.*;
import java.net.*;
public class RemoteFileClient {
     protected BufferedReader socketReader;
     protected PrintWriter socketWriter;
     protected String hostIp;
     protected int hostPort;
     //構造方法
     public RemoteFileClient(String hostIp, int hostPort) {
         this.hostIp = hostIp;
         this.hostPort=hostPort;
     }
     //向服務器請求文件的內容
     public String getFile(String fileNameToGet) {
         StringBuffer fileLines = new StringBuffer();
         try {
             socketWriter.println(fileNameToGet);            
             socketWriter.flush();
             String line = null;
             while((line=socketReader.readLine())!=null)
                 fileLines.append(line+"\n");
         }
         catch(IOException e) {
             System.out.println("Error reading from file: "+fileNameToGet);
         }
         return fileLines.toString();
     }
     //連接到遠程服務器
     public void setUpConnection() {
         try {
             Socket client = new Socket(hostIp,hostPort);
             socketReader = new BufferedReader(new InputStreamReader(client.getInputStream()));
             socketWriter = new PrintWriter(client.getOutputStream());
         }
         catch(UnknownHostException e) {
             System.out.println("Error1 setting up socket connection: unknown host at "+hostIp+":"+hostPort);
         }
         catch(IOException e) {
             System.out.println("Error2 setting up socket connection: "+e);
         }
     }
     //斷開遠程服務器
     public void tearDownConnection() {
         try {
             socketWriter.close();
             socketReader.close();
         }catch(IOException e) {            
             System.out.println("Error tearing down socket connection: "+e);
         }
     }
     public static void main(String args[]) {
         RemoteFileClient remoteFileClient = new RemoteFileClient("127.0.0.1",1001);
         remoteFileClient.setUpConnection();
         StringBuffer fileContents = new StringBuffer();
         fileContents.append(remoteFileClient.getFile("RemoteFileServer.java"));        
         //remoteFileClient.tearDownConnection();
         System.out.println(fileContents);
     }
}
首先我們導入 java.net 和 java.io。java.net 包為您提供您需要的套接字工具。java.io 包為您提供對流進行讀寫的工具,這是您與 TCP 套接字通信的唯一途徑。
我們給我們的類實例變量以支持對套接字流的讀寫和存儲我們將連接到的遠程主機的詳細信息。
我們類的構造器有兩個參數:遠程主機的IP地址和端口號各一個,而且構造器將它們賦給實例變量。
我們的類有一個 main() 方法和三個其它方法。稍后我們將探究這些方法的細節?,F在您只需知道 setUpConnection() 將連接到遠程服務器,getFile() 將向遠程服務器請求 fileNameToGet 的內容以及 tearDownConnection() 將從遠程服務器上斷開。
實現 main()
這里我們實現 main() 方法,它將創建 RemoteFileClient 并用它來獲取遠程文件的內容,然后打印結果。main() 方法用主機的 IP 地址和端口號實例化一個新 RemoteFileClient(客戶機)。然后,我們告訴客戶機建立一個到主機的連接。接著,我們告訴客戶機獲取主機上一個指定文件的內容。最后,我們告訴客戶機斷開它到主機的連接。我們把文件內容打印到控制臺,只是為了證明一切都是按計劃進行的。
建立連接
這里我們實現 setUpConnection() 方法,它將創建我們的 Socket 并讓我們訪問該套接字的流:
     public void setUpConnection() {
         try {
             Socket client = new Socket(hostIp,hostPort);
             socketReader = new BufferedReader(new InputStreamReader(client.getInputStream()));
             socketWriter = new PrintWriter(client.getOutputStream());
         }
         catch(UnknownHostException e) {
             System.out.println("Error1 setting up socket connection: unknown host at "+hostIp+":"+hostPort);
         }
         catch(IOException e) {
             System.out.println("Error2 setting up socket connection: "+e);
         }
     }
setUpConnection() 方法用主機的 IP 地址和端口號創建一個 Socket:
Socket client = new Socket(hostIp, hostPort);
我們把 Socket 的 InputStream 包裝進 BufferedReader 以使我們能夠讀取流的行。然后,我們把 Socket 的 OutputStream 包裝進 PrintWriter 以使我們能夠發送文件請求到服務器:
socketReader = new BufferedReader(new InputStreamReader(client.getInputStream()));socketWriter = new PrintWriter(client.getOutputStream());
請記住我們的客戶機和服務器只是來回傳送字節。客戶機和服務器都必須知道另一方即將發送的是什么以使它們能夠作出適當的響應。在這個案例中,服務器知道我們將發送一條有效的文件路徑。
當您實例化一個 Socket 時,將拋出 UnknownHostException。這里我們不特別處理它,但我們打印一些信息到控制臺以告訴我們發生了什么錯誤。同樣地,當我們試圖獲取 Socket 的 InputStream 或 OutputStream 時,如果拋出了一個一般 IOException,我們也打印一些信息到控制臺。
與主機交談
這里我們實現 getFile() 方法,它將告訴服務器我們想要什么文件并在服務器傳回其內容時接收該內容。
     public String getFile(String fileNameToGet) {
         StringBuffer fileLines = new StringBuffer();
         try {
             socketWriter.println(fileNameToGet);            
             socketWriter.flush();
             String line = null;
             while((line=socketReader.readLine())!=null)
                 fileLines.append(line+"\n");
         }
         catch(IOException e) {
             System.out.println("Error reading from file: "+fileNameToGet);
         }
         return fileLines.toString();
     }
對getFile()方法的調用要求一個有效的文件路徑String。它首先創建名為fileLines的 StringBuffer,fileLines 用于存儲我們讀自服務器上的文件的每一行。
StringBuffer fileLines = new StringBuffer();
在 try{}catch{} 塊中,我們用 PrintWriter 把請求發送到主機,PrintWriter 是我們在創建連接期間建立的。
     socketWriter.println(fileNameToGet);     socketWriter.flush();
請注意這里我們是 flush() 該 PrintWriter,而不是關閉它。這迫使數據被發送到服務器而不關閉 Socket。
一旦我們已經寫到 Socket,我們就希望有一些響應。我們不得不在 Socket 的 InputStream 上等待它,我們通過在 while 循環中調用 BufferedReader 上的 readLine() 來達到這個目的。我們把每一個返回行附加到 fileLines StringBuffer(帶有一個換行符以保護行):
     String line = null;     while((line=socketReader.readLine())!=null)         fileLines.append(line+"\n");
斷開連接
這里我們實現 tearDownConnection() 方法,它將在我們使用完畢連接后負責“清除”。tearDownConnection()方法只是分別關閉我們在Socket的InputStream和OutputStream上創建的 BufferedReader和PrintWriter。這樣做會關閉我們從Socket獲取的底層流,所以我們必須捕捉可能的 IOException。
總結一下客戶機
我們的類研究完了。在我們繼續往前討論服務器端的情況之前,讓我們回顧一下創建和使用 Socket 的步驟:
1.     用您想連接的機器的 IP 地址和端口實例化 Socket(如有問題則拋出 Exception)。
2.     獲取 Socket 上的流以進行讀寫。
3.     把流包裝進 BufferedReader/PrintWriter 的實例,如果這樣做能使事情更簡單的話。
4.     對 Socket 進行讀寫。
5.     關閉打開的流。
5 創建服務器Socket
創建 RemoteFileServer 類
import java.io.*;
import java.net.*;
public class RemoteFileServer {    
     int listenPort;
     public RemoteFileServer(int listenPort) {
         this.listenPort=listenPort;
     }
     //允許客戶機連接到服務器,等待客戶機請求    
     public void acceptConnections() {
         try {
             ServerSocket server = new ServerSocket(listenPort);
             Socket incomingConnection = null;
             while(true) {
                 incomingConnection = server.accept();
                 handleConnection(incomingConnection);
             }
         }
         catch(BindException e) {
             System.out.println("Unable to bind to port "+listenPort);
         }
         catch(IOException e) {
             System.out.println("Unable to instantiate a ServerSocket on port: "+listenPort);  
            
         }
     }
     //與客戶機Socket交互以將客戶機所請求的文件的內容發送到客戶機
     public void handleConnection(Socket incomingConnection) {
         try {
             OutputStream outputToSocket = incomingConnection.getOutputStream();
             InputStream inputFromSocket = incomingConnection.getInputStream();
             BufferedReader streamReader = new BufferedReader(new InputStreamReader(inputFromSocket));
             FileReader fileReader = new FileReader(new File(streamReader.readLine()));
             BufferedReader bufferedFileReader = new BufferedReader(fileReader);
             PrintWriter streamWriter = new PrintWriter(incomingConnection.getOutputStream());
             String line = null;
             while((line=bufferedFileReader.readLine())!=null){
                 streamWriter.println(line);
             }
             fileReader.close();
             streamWriter.close();
             streamReader.close();
         }
         catch(Exception e) {
             System.out.println("Error handling a client: "+e);
             e.printStackTrace();
         }
     }
     public static void main(String args[]) {
         RemoteFileServer server = new RemoteFileServer(1001);
         server.acceptConnections();
     }
}
跟客戶機中一樣,我們首先導入java.net的java.io。接著,我們給我們的類一個實例變量以保存端口,我們從該端口偵聽進入的連接。缺省情況下,端口是1001。
我們的類有一個main()方法和兩個其它方法。稍后我們將探究這些方法的細節?,F在您只需知道acceptConnections()將允許客戶機連接到服務器以及handleConnection()與客戶機Socket交互以將您所請求的文件的內容發送到客戶機。
實現 main()
這里我們實現main()方法,它將創建RemoteFileServer并告訴它接受連接:服務器端的main()方法中,我們實例化一個新RemoteFileServer,它將在偵聽端口(1001)上偵聽進入的連接請求。然后我們調用acceptConnections()來告訴該server進行偵聽。
接受連接
這里我們實現 acceptConnections() 方法,它將創建一個 ServerSocket 并等待連接請求:
     public void acceptConnections() {
         try {
             ServerSocket server = new ServerSocket(listenPort);
             Socket incomingConnection = null;
             while(true) {
                 incomingConnection = server.accept();
                 handleConnection(incomingConnection);
             }
         }
         catch(BindException e) {
             System.out.println("Unable to bind to port "+listenPort);
         }
         catch(IOException e) {
             System.out.println("Unable to instantiate a ServerSocket on port: "+listenPort);  
            
         }
     }
acceptConnections()用欲偵聽的端口號來創建ServerSocket。然后我們通過調用該ServerSocket的accept()來告訴它開始偵聽。accept()方法將造成阻塞直到來了一個連接請求。此時,accept()返回一個新的Socket,這個Socket綁定到服務器上一個隨機指定的端口,返回的Socket被傳遞給handleConnection()。請注意我們在一個無限循環中處理對連接的接受。這里不支持任何關機。
無論何時如果您創建了一個無法綁定到指定端口(可能是因為別的什么控制了該端口)的 ServerSocket,Java代碼都將拋出一個錯誤。所以這里我們必須捕捉可能的BindException。就跟在客戶機端上時一樣,我們必須捕捉IOException,當我們試圖在ServerSocket上接受連接時,它就會被拋出。請注意,您可以通過用毫秒數調用setSoTimeout()來為accept()調用設置超時,以避免實際長時間的等待。調用setSoTimeout()將使accept()經過指定占用時間后拋出IOException。
處理連接
這里我們實現handleConnection()方法,它將用連接的流來接收輸入和寫輸出:
     public void handleConnection(Socket incomingConnection) {
         try {
             OutputStream outputToSocket = incomingConnection.getOutputStream();
             InputStream inputFromSocket = incomingConnection.getInputStream();
             BufferedReader streamReader = new BufferedReader(new InputStreamReader(inputFromSocket));
             FileReader fileReader = new FileReader(new File(streamReader.readLine()));
             BufferedReader bufferedFileReader = new BufferedReader(fileReader);
             PrintWriter streamWriter = new PrintWriter(incomingConnection.getOutputStream());
             String line = null;
             while((line=bufferedFileReader.readLine())!=null){
                 streamWriter.println(line);
             }
             fileReader.close();
             streamWriter.close();
             streamReader.close();
         }
         catch(Exception e) {
             System.out.println("Error handling a client: "+e);
             e.printStackTrace();
         }
     }
跟在客戶機中一樣,我們用getOutputStream()和getInputStream()來獲取與我們剛創建的Socket相關聯的流。跟在客戶機端一樣,我們把InputStream包裝進BufferedReader,把OutputStream包裝進PrintWriter。在服務器端上,我們需要添加一些代碼,用來讀取目標文件和把內容逐行發送到客戶機。這里是重要的代碼:
     FileReader fileReader = new FileReader(new File(streamReader.readLine()));     BufferedReader bufferedFileReader = new BufferedReader(fileReader);     String line = null;     while((line=bufferedFileReader.readLine())!=null) {         streamWriter.println(line);     }
這些代碼值得詳細解釋。讓我們一點一點來看:
     FileReader fileReader = new FileReader(new File(streamReader.readLine()));
首先,我們使用Socket 的InputStream的BufferedReader。我們應該獲取一條有效的文件路徑,所以我們用該路徑名構造一個新File。我們創建一個新FileReader來處理讀文件的操作。
     BufferedReader bufferedFileReader = new BufferedReader(fileReader);
這里我們把FileReader包裝進BufferedReader以使我們能夠逐行地讀該文件。
接著,我們調用BufferedReader的readLine()。這個調用將造成阻塞直到有字節到來。我們獲取一些字節之后就把它們放到本地的line變量中,然后再寫出到客戶機上。完成讀寫操作之后,我們就關閉打開的流。
請注意我們在完成從Socket的讀操作之后關閉streamWriter和streamReader。您或許會問我們為什么不在讀取文件名之后立刻關閉streamReader。原因是當您這樣做時,您的客戶機將不會獲取任何數據。如果您在關閉streamWriter之前關閉streamReader,則您可以往Socket寫任何東西,但卻沒有任何數據能通過通道(通道被關閉了)。
總結一下服務器
在我們接著討論另一個更實際的示例之前,讓我們回顧一下創建和使用ServerSocket的步驟:
1.     用一個您想讓它偵聽傳入客戶機連接的端口來實例化一個ServerSocket(如有問題則拋出 Exception)。
2.     調用ServerSocket的accept()以在等待連接期間造成阻塞。
3.     獲取位于該底層Socket的流以進行讀寫操作。
4.     按使事情簡單化的原則包裝流。
5.     對Socket進行讀寫。
6.     關閉打開的流(并請記住,永遠不要在關閉Writer之前關閉Reader)。


liujg 2009-01-04 12:55 發表評論
]]>
snmp4jhttp://m.tkk7.com/tbest/articles/240403.htmlliujgliujgThu, 13 Nov 2008 14:35:00 GMThttp://m.tkk7.com/tbest/articles/240403.htmlhttp://m.tkk7.com/tbest/comments/240403.htmlhttp://m.tkk7.com/tbest/articles/240403.html#Feedback0http://m.tkk7.com/tbest/comments/commentRss/240403.htmlhttp://m.tkk7.com/tbest/services/trackbacks/240403.htmlProvides classes and interfaces for creating, sending, and receiving SNMP messages.

The org.snmp4j classes are capable of creating, sending, and receiving SNMPv1/v2c/v3 messages. A SNMP message is composed of its message header and its PDU payload. This package contains three main groups of classes and interfaces:

  • Classes for SNMP message and target creation
  • Classes for SNMP message sending (command generation)
  • Classes for SNMP message dispatching (command responding)

The following UML package diagram illustrates the dependencies between the packages of the core SNMP4J API. Users of the API normally only need to use the org.snmp4j and the org.snmp4j.smi packages directly.

 

The following UML class diagram shows the most important classes of the org.snmp4j package and their relationships (relationships to other packages are not shown):.

SNMP Messages and Targets

To exchange a SNMP message with a remote system, that system has to be identified, retransmission, and timeout policy information about the message exchange has to be specified. A remote system is specified with SNMP4J by creating a Target instance appropriate for the SNMP protocol to be used.

  • For SNMPv1 and SNMPv2c the CommunityTarget has to be used which provides community information in addition to the address, retransmission, and timeout policy information defined by the Target interface.
  • For SNMPv3 the UserTarget has to be used instead. It extends the SecureTarget abstract class and provides the following User Based Security Model (USM) user information: security name, security level, security model (i.e. USM), and authoritative engine ID.

A SNMP message consists of the message's payload, the SNMP Protocol Data Unit (PDU) and a message header. Simplified said, in SNMP4J the message header information is represented by Target instances and the PDU is represented by one of the following classes:

  • PDUv1 (SNMPv1)
  • PDU (SNMPv2c)
  • ScopedPDU (SNMPv3)
Thus, in order to be able to send a SNMP message with SNMP4J, a PDU instance and a Target instance have to be created.

PDU Examples (PDU 使用的例子)

  • SNMPv1/v2c GETNEXT PDU
    import org.snmp4j.PDU;
        import org.snmp4j.smi.*;
        ...
        PDU pdu = new PDU();
        pdu.add(new VariableBinding(new OID("1.3.6.1.2.1.1.1"))); // sysDescr
        pdu.add(new VariableBinding(new OID("1.3.6.1.2.1.2.1"))); // ifNumber
        pdu.setType(PDU.GETNEXT);
        ...
        
  • SNMPv3 GETBULK PDU
    import org.snmp4j.ScopedPDU;
        import org.snmp4j.smi.*;
        ...
        ScopedPDU pdu = new ScopedPDU();
        pdu.add(new VariableBinding(new OID("1.3.6.1.2.1.2.1"))); // ifNumber
        pdu.add(new VariableBinding(new OID("1.3.6.1.2.1.2.2.1.10"))); // ifInOctets
        pdu.add(new VariableBinding(new OID("1.3.6.1.2.1.2.2.1.16"))); // ifOutOctets
        pdu.setType(PDU.GETBULK);
        pdu.setMaxRepetitions(50);
        // Get ifNumber only once
        pdu.setNonRepeaters(1);
        // set context non-default context (default context does not need to be set)
        pdu.setContextName(new OctetString("subSystemContextA"));
        // set non-default context engine ID (to use targets authoritative engine ID
        // use an empty (size == 0) octet string)
        pdu.setContextEngineID(OctetString.fromHexString("80:00:13:70:c0:a8:01:0d"));
        ...
        
  • SNMPv1 TRAP PDU ()
    import org.snmp4j.PDUv1;
        ...
        PDUv1 pdu = new PDUv1();
        pdu.setType(PDU.V1TRAP);
        pdu.setGenericTrap(PDUv1.COLDSTART);
        ...
        
  • SNMPv2c/SNMPv3 INFORM PDU
    import org.snmp4j.ScopedPDU;
        ...
        ScopedPDU pdu = new ScopedPDU();
        pdu.setType(PDU.INFORM);
        // sysUpTime
        long sysUpTime = (System.currentTimeMillis() - startTime) / 10;
        pdu.add(new VariableBinding(SnmpConstants.sysUpTime, new TimeTicks(sysUpTime)));
        pdu.add(new VariableBinding(SnmpConstants.snmpTrapOID, SnmpConstants.linkDown));
        // payload
        pdu.add(new VariableBinding(new OID("1.3.6.1.2.1.2.2.1.1"+downIndex),
        new Integer32(downIndex)));
        ...
        

Target Examples (對象例子)

  • Community Target
    CommunityTarget target = new CommunityTarget();
        target.setCommunity(new OctetString("public"));
        target.setAddress(targetAddress);
        target.setVersion(SnmpConstants.version1);
        
  • User Target
    UserTarget target = new UserTarget();
        target.setAddress(targetAddress);
        target.setRetries(1);
        // set timeout to 500 milliseconds -> 2*500ms = 1s total timeout
        target.setTimeout(500);
        target.setVersion(SnmpConstants.version3);
        target.setSecurityLevel(SecurityLevel.AUTH_PRIV);
        target.setSecurityName(new OctetString("MD5DES"));
        

Sending SNMP messages

SNMP message are sent with SNMP4J by using a instance of the SNMP Session interface. The default implementation of this interface is the Snmp class.

To setup a Snmp instance it is sufficient to call its constructor with a TransportMapping instance. The transport mapping is used by the SNMP session to send (and receive) SNMP message to a remote systems by using a transport protocol, for example the User Datagram Protocol (UDP).

A SNMP4J Snmp instance supports SNMP v1, v2c, and v3 by default. By sub-classing Snmp other combinations of those SNMP protocol versions can be supported.

With SNMP4J, SNMP messages can be sent synchronously (blocking) and asynchronously (non-blocking). The Snmp class does not use an internal thread to process responses on asynchronous and synchronous requests. Nevertheless it uses the receiver threads of the transport mappings to process responses.

Asynchronous responses are returned by calling a callback method on an object instance that implements the ResponseListener interface. The callback is carried out on behalf of the transport mapping thread that received the response packet from the wire. Thus, if the called method blocks, the delivery of synchronous and asynchronous messages received on the listen port of that transport mapping will be also blocked. Other transport mapping will not be affected. Blocking can be avoided by either using synchronous messages only or by decoupling the processing within the callback method.

Example for Sending a Synchronous Message (發送同步消息)

import org.snmp4j.*;
...
Snmp snmp = new Snmp(new DefaultUdpTransportMapping());
...
ResponseEvent response = snmp.send(requestPDU, target);
if (response.getResponse() == null) {
// request timed out
...
}
else {
System.out.println("Received response from: "+
response.getPeerAddress());
// dump response PDU
System.out.println(response.getResponse().toString());
}

Example for Sending an Asynchronous Message (發送異步消息)

import org.snmp4j.*;
import org.snmp4j.event.*;
...
Snmp snmp = new Snmp(new DefaultUdpTransportMapping());
...
ResponseListener listener = new ResponseListener() {
public void onResponse(ResponseEvent event) {
PDU response = event.getResponse();
PDU request = event.getRequest();
if (response == null) {
System.out.println("Request "+request+" timed out");
}
else {
System.out.println("Received response "+response+" on request "+
request);
}
};
snmp.sendPDU(request, target, null, listener);
...

Receiving SNMP messages(接收SNMP信息)

SNMP4J receives SNMP messages through the listen port of transport mappings. In order to be able to receive responses or requests, that port needs to be set into listen mode. This has to be done by calling the listen() method of the TransportMapping instance to start the transport mappings internal listen thread. The internal thread is stopped and the listen port is closed by calling the close() method on the TransportMapping instance or the associated Snmp instance.

The transport mapping just receives the SNMP mesage as a stream of bytes and forwards the message to associated MessageDispatcher instances. By default, SNMP4J uses one instance of the MessageDispatcherImpl class for decoding and dispatching incoming messages. That instance is created and used internally by the Snmp class.

The Snmp class processes responses to outstanding requests and forwards PDUs of other SNMP messages to registered CommandResponder listener instances. To receive SNMP messages it is thus sufficient to

  1. Create a TransportMapping and initialize its listen port by calling TransportMapping.listen().
  2. Create a Snmp instance with the above TransportMapping.
  3. Instantiate a class that implements the CommandResponder interface and register it with the Snmp instance by calling Snmp.addCommandResponder(CommandResponder).

When a unhandled SNMP message (thus a SNMP message where no corresponding outstanding request exists) is received, then the processPdu(CommandResponderEvent) method of the CommandResponder will be called with the decoded PDU and additional information about the received SNMP message provided by the message processing model that has decoded the SNMP message.

Example for Receiving SNMP Messages (接收SNMP消息的例子)

import org.snmp4j.*;
import org.snmp4j.smi.*;
import org.snmp4j.mp.SnmpConstants;
...
TransportMapping transport =
new DefaultUdpTransportMapping(new UdpAddress("0.0.0.0/161"));
Snmp snmp = new Snmp(transport);
if (version == SnmpConstants.version3) {
byte[] localEngineID =
((MPv3)snmp.getMessageProcessingModel(MessageProcessingModel.MPv3)).createLocalEngineID();
USM usm = new USM(SecurityProtocols.getInstance(),
new OctetString(localEngineID), 0);
SecurityModels.getInstance().addSecurityModel(usm);
snmp.setLocalEngine(localEngineID, 0, 0);
// Add the configured user to the USM
...
}
snmp.addCommandResponder(this);
transport.listen();
...
public synchronized void processPdu(CommandResponderEvent e) {
PDU command = e.getPdu();
if (command != null) {
...
}
}
以下是 org.snmp4j.smi 包下的說明:
Provides classes for the representation of SMIv1/v2 data types (which also includes some basic ASN.1 primitive data types).

The org.snmp4j.smi classes are capable of BER encoding and decoding themself to/from a byte stream. In addition, the SMI data type classes provide convenient functions for manipulating their content.

The VariantVariable is a special class that can be used in command responder applications to intercept access to a SMI value.

Variable Binding Examples

import org.snmp4j.smi.*;
...
VariableBinding vb = new VariableBinding(new OID("1.3.6.1.2.1.1.4.0"));
vb.setValue(new OctetString("SNMP4J Text"));
...
vb = new VariableBinding();
vb.setOid(new OID(new int[] { 1,3,6,1,2,1,1,2,0 }));
...
vb = new VariableBinding(vb.getOid(), new IpAddress("255.255.255.255"));
...
vb = new VariableBinding(vb.getOid(), new Gauge32(2^32-1));
int syntax = vb.getSyntax();
if (syntax != SMIConstants.SYNTAX_GAUGE32) {
// never reached
}
else {
long value = ((UnsignedInteger32)vb.getValue()).getValue();
System.out.println(vb.getOid() + " = " + value);
// prints: 1.3.6.1.2.1.1.2.0 = 4294967295
}
...

The following UML class diagram shows the most important classes of the org.snmp4j.smi package and their relationships (relationships to other packages are not shown):

UML類圖

以下是 org.snmp.asn1 包中的說明
Provides classes and interfaces for the mapping between Abstract Syntax Notation One (ASN.1) formatted values and their transfer syntax according to the Basic Encoding Rules (BER).

The org.snmp4j.asn1 classes are capable of serializing of ASN.1 formatted values into a byte stream and deserializing the same from a byte stream. There are three groups of classes/interfaces in this package:

  • The BER class implements the BER serialization and deserialization by providing static methods for encoding/decoding of primitive ASN.1 and Structure of Management Information (SMI) data types.
  • The BERSerializable interface provides a common interface for all objects that are (de)serializable according to the Basic Encoding Rules (BER).
  • The BERInputStream and the BEROutputStream provide optimized implementations for the serialization and deserialization of the InputStream and OutputStream abstract classes.

 

The following UML class diagram shows the most important classes of the org.snmp4j.asn1 package and their relationships (relationships to other packages are not shown):

以下是 org.snmp4j.mp 包中的說明
Provides classes and interfaces for the SNMP message processing.

The org.snmp4j.mp classes provide services to process SNMP messages. The services provided are defined in the MessageProcessingModel interface and include the following:

  • Prepare data elements from an incoming SNMP message as described in RFC3412 §7.2.
  • Prepare a response message as defined in RFC3412 §7.1.
  • Prepare an outgoing message as defined in RFC3412 §7.1.

 

This interface is implemented by the message processing model classes for the SNMP versions 1, v2c, and v3: MPv1, MPv2c, and MPv3.

The MessageDispatcherImpl chooses which message processing model it uses to process an outgoing or incoming SNMP message based on the SNMP version of the message. The SNMP version is either extracted from the message header (incoming message) or from the Target instance associated with the outgoing PDU (ougoing message).

To be able to match requests and responses SNMP uses request IDs. Since request IDs are created by the command generator, the request IDs are unique within such a command generator only. SNMP4J therefore has to abstract from request IDs and uses PduHandle instances instead.

If a PDU is processed for sending by the SNMP4J MessageDispatcherImpl and the PDU's request ID is set to 0, then a SNMP4J application wide unique ID is generated and set as request ID of the supplied PDU. In any case, the PDU's request ID will be used as transaction ID of the outgoing message. The transaction ID identifies a messages PduHandle.

If a PDU is received by the SNMP4J MessageDispatcherImpl a unique transaction ID is generated so that command responders as well as the message processing model can match requests and responses.

The following UML class diagram shows the most important classes of the org.snmp4j.mp package and their relationships (relationships to other packages are not shown):

以下是 org.snmp4j.transport 包中的說明
Provides transport protocol mappings for SNMP.

The org.snmp4j.transport classes are capable of sending and receiving byte messages to and from a network using transport mapping specific transport protocol. All SNMP4J transport mappings have to implement the org.snmp4j.TransportMapping interface. SNMP4J supports two transport mappings for the transport protocols UDP and TCP:

  • The UDP transport mapping is the default SNMP transport mapping. It is implemented by the DefaultUdpTransportMapping class.
  • The TCP transport mapping is implemented by the DefaultTcpTransportMapping using the java.nio package.

Additional transport mappings can be easily added. It is sufficient to implement the org.snmp4j.TransportMapping interface and add an instance of that class to the Snmp (or MessageDispatcher) object. To be able to lookup a transport mapping by an Address class via the TransportMappings (as Snmp does for notification listeners), a transport mapping has to be registered in a transport mapping registration file. The default file is transports.properties in the org.snmp4j.transport package. To use a different file, set the system property org.snmp4j.transportMappings.

Connection-oriented transport mappings like TCP should implement the ConnectionOrientedTransportMapping interface to support MessageLengthDecoder and TransportStateListener.

The following UML class diagram shows the classes of the org.snmp4j.transport package and their relationships (relationships to other packages are not shown):

UML Class Diagram org.snmp4j.transport
以下是 org.snmp4j.util 包中的說明
Contains table retrieval utilities and multi-threading support classes as well as miscellaneous utility classes.

The org.snmp4j.util contains the following groups of classes:

  • Classes for SNMP table retrieval. The class TableUtils can be used to asynchronously retrieve table data effeciently row by row.
  • Classes for support of multi-threaded message dispatching. The class MultiThreadedMessageDispatcher implements the MessageDispatcher interface and uses the MessageDispatcherImpl class to dispatch incoming message using the threads of a ThreadPool.

The following UML class diagram shows the classes of the org.snmp4j.util package and their relationships (relationships to other packages are not shown):



liujg 2008-11-13 22:35 發表評論
]]>
Serializable 相關(http://www.lupaworld.com/25070/viewspace_16379.html)http://m.tkk7.com/tbest/articles/212171.htmlliujgliujgWed, 02 Jul 2008 09:39:00 GMThttp://m.tkk7.com/tbest/articles/212171.htmlhttp://m.tkk7.com/tbest/comments/212171.htmlhttp://m.tkk7.com/tbest/articles/212171.html#Feedback0http://m.tkk7.com/tbest/comments/commentRss/212171.htmlhttp://m.tkk7.com/tbest/services/trackbacks/212171.html類通過實現 java.io.Serializable 接口以啟用其序列化功能。未實現此接口的類將無法使其任何狀態序列化或反序列化??尚蛄谢惖乃凶宇愋捅旧矶际强尚蛄谢摹P蛄谢涌跊]有方法或字段,僅用于標識可序列化的語義.
Java的"對象序列化"能讓你將一個實現了Serializable接口的對象轉換成一組byte,這樣日后要用這個對象時候,你就能把這些byte數據恢復出來,并據此重新構建那個對象了。
要想序列化對象,你必須先創建一個OutputStream,然后把它嵌進ObjectOutputStream。這時,你就能用writeObject( )方法把對象寫入OutputStream了。
writeObject 方法負責寫入特定類的對象的狀態,以便相應的 readObject 方法可以還原它。通過調用 out.defaultWriteObject 可以調用保存 Object 的字段的默認機制。該方法本身不需要涉及屬于其超類或子類的狀態。狀態是通過使用 writeObject 方法或使用 DataOutput 支持的用于基本數據類型的方法將各個字段寫入 ObjectOutputStream 來保存的。
http://www.lupaworld.com/25070/viewspace_16379.html



liujg 2008-07-02 17:39 發表評論
]]>
關于forward和redirect的區別(轉載)http://m.tkk7.com/tbest/articles/212168.htmlliujgliujgWed, 02 Jul 2008 09:19:00 GMThttp://m.tkk7.com/tbest/articles/212168.htmlhttp://m.tkk7.com/tbest/comments/212168.htmlhttp://m.tkk7.com/tbest/articles/212168.html#Feedback0http://m.tkk7.com/tbest/comments/commentRss/212168.htmlhttp://m.tkk7.com/tbest/services/trackbacks/212168.htmlforward是服務器請求資源,服務器直接訪問目標地址的URL,把那個URL的響應內容讀取過來,然后把這些內容再發給瀏覽器,瀏覽器根本不知道服務器發送的內容是從哪兒來的,所以它的地址欄中還是原來的地址。還有,轉發是在web應用程序之內進行的,可以訪問web應用程序所設定的內部目錄,像是WEB-INF目錄,只能在Web應用程序中進行,不能指定至其它的Web應用程序的地址。
Tsj:J\vn,CR*|C0redirect就是服務端根據邏輯,發送一個狀態碼,告訴瀏覽器重新去請求那個地址,一般來說瀏覽器會用剛才請求的所有參數重新請求,所以session,request參數都可以獲取。web應用程序會要求客戶端瀏覽器重新發出請求地址,客戶端會重新連接至所指定的地址,因此瀏覽器的地址會出現重新導向的信息,重新導向后的請求由瀏覽器發出,所以不能訪問Web應用程序中的隱藏目錄,像是WEB-INF,重新是由瀏覽器重新要求一個網頁,可以指定至其他的Web應用程序地址。LUPA開源社區%ZY-m!N?+M v2D+H R%[
LUPA開源社區Lz-x9O(p;[ S

'M"O$M.Iw,T;K`0RequestDispatcher.forward()方法和HttpServletResponse.sendRedirect()方法的區別是:前者僅是容器中控制權的轉向,在客戶端瀏覽器地址欄中不會顯示出轉向后的地址,他是不會改變Request的值,如果你需要在下一個頁面中能從中獲取新的信息的話,你可以Request.setAttribute()來放置一些標志,這樣從下一個頁面中獲?。缓笳邉t是完全的跳轉,瀏覽器將會得到跳轉的地址,并重新發送請求鏈接。這樣,從瀏覽器的地址欄中可以看到跳轉后的鏈接地址。所以,前者更加高效,在前者可以滿足需要時,盡量使用Request Dispatcher.forward()方法,并且,這樣也有助于隱藏實際的鏈接。在有些情況下,比如,需要跳轉到一個其它服務器上的資源,則必須使用 HttpServletResponse.sendRequest()方法。LUPA開源社區;Xh~OI

Thi5~X0
1、forward與include共亨Request范圍內的對象,而redirect則不行,即:如果一個javabean被聲明為request范圍的話,則被forward到的資源也可以訪問這個javabean,而redriect則不行。
Y7u(H9?&F8b02、forward與include基本上都是轉發到context內部的資源,而redirect可以重定向到外部的資源,如: req.sendRedriect("http://www.mocuai.com");LUPA開源社區C {4_jC^+N



liujg 2008-07-02 17:19 發表評論
]]>
主站蜘蛛池模板: 18女人水真多免费高清毛片| 亚洲AV第一页国产精品| 99久久免费精品视频| 在线播放国产不卡免费视频| 伊人久久亚洲综合影院首页| 亚洲永久永久永久永久永久精品| 老司机亚洲精品影视www| 在线观看永久免费视频网站| 蜜桃视频在线观看免费网址入口| 久久永久免费人妻精品| 又长又大又粗又硬3p免费视频| 色欲aⅴ亚洲情无码AV| 亚洲avav天堂av在线网爱情| 亚洲免费精彩视频在线观看| 亚洲另类激情综合偷自拍图| 亚洲日韩人妻第一页| 亚洲av无码不卡私人影院| 香蕉视频在线观看免费国产婷婷 | 成年在线观看网站免费| 无人在线观看免费高清| 99在线免费视频| 国产免费AV片在线观看播放| 黄色一级免费网站| 国产精品亚洲专区无码唯爱网| 亚洲人成网站色7799| 91亚洲国产成人久久精品| 亚洲视频免费播放| 亚洲视频免费在线播放| 亚洲福利电影一区二区?| 久久亚洲国产精品成人AV秋霞| 亚洲黄色在线观看| 亚洲精品熟女国产| 亚洲国产精品久久久久秋霞影院| 亚洲色偷偷av男人的天堂| 亚洲视频一区二区在线观看| 亚洲资源在线观看| 亚洲午夜电影一区二区三区| 亚洲an日韩专区在线| 亚洲av无码成人精品区一本二本 | 免费观看激色视频网站bd | 亚洲香蕉久久一区二区三区四区|