Sun Cluster 資料服務開發者指南 (適用於 Solaris 作業系統)

建立使用 CRNP 的 Java 應用程式之範例

以下範例說明如何開發使用 CRNP 的名為 CrnpClient 的簡易 Java 應用程式。該應用程式使用叢集中的 CRNP 伺服器註冊事件回呼,偵聽事件回呼並透過輸出事件內容處理事件。在終止之前,該應用程式會取消註冊其對事件回呼的要求。

檢閱此範例時,請注意以下幾點︰

Procedure如何設置環境

步驟
  1. 下載並安裝 JAXP、正確版本的 Java 編譯器、虛擬機器。

    您可在 http://java.sun.com/xml/jaxp/index.html 中找到說明。


    備註 –

    此範例要求至少是 Java 1.3.1 版本。


  2. 從原始碼檔案所在目錄,鍵入以下內容︰


    % javac -classpath jaxp-root/dom.jar:jaxp-rootjaxp-api. \
    jar:jaxp-rootsax.jar:jaxp-rootxalan.jar:jaxp-root/xercesImpl \
    .jar:jaxp-root/xsltc.jar -sourcepath . source-filename.java
    

    其中,jaxp-root 是 JAXP jar 檔案所在目錄的絕對或相對路徑,而 source-filename 是 Java 原始碼檔案的名稱。

    編譯指令行中的 classpath 可確保編譯器可以找到 JAXP 類別。

  3. 執行應用程式時,請指定 classpath,以便應用程式可以載入正確的 JAXP 類別檔案 (請注意,classpath 中的第一個路徑為目前目錄)︰


    % java -cp .:jaxp-root/dom.jar:jaxp-rootjaxp-api. \
    jar:jaxp-rootsax.jar:jaxp-rootxalan.jar:jaxp-root/xercesImpl \
    .jar:jaxp-root/xsltc.jar source-filename arguments
    

    既然已配置了環境,您可以開發應用程式。

Procedure如何開始開發應用程式

在範例的此部分中,您可使用剖析指令行引數並建構 CrnpClient 物件的主要方法,建立名為 CrnpClient 的基本類別。此物件將指令行引數傳送至類別、等待使用者終止該應用程式、在 CrnpClient 上呼叫 shutdown,然後結束。

CrnpClient 類別的建構元需要執行下列作業:

步驟

    建立實施前導邏輯的 Java 程式碼。

    以下範例顯示 CrnpClient 類別的架構程式碼。在建構子和關閉方法中參照的四個輔助程式方法的實作將稍後在本章中展示。請注意,將會展示您需要的用於匯入所有套裝軟體的程式碼。

    import javax.xml.parsers.*;
    import javax.xml.transform.*;
    import javax.xml.transform.dom.*;
    import javax.xml.transform.stream.*;
    import org.xml.sax.*;
    import org.xml.sax.helpers.*;
    import org.w3c.dom.*;
    import java.net.*;
    import java.io.*;
    import java.util.*;
    
    class CrnpClient
    {
            public static void main(String []args)
            {
                    InetAddress regIp = null;
                    int regPort = 0, localPort = 0;
                    try {
                            regIp = InetAddress.getByName(args[0]);
                            regPort = (new Integer(args[1])).intValue();
                            localPort = (new Integer(args[2])).intValue();
                    } catch (UnknownHostException e) {
                            System.out.println(e);
                            System.exit(1);
                    }
                    CrnpClient client = new CrnpClient(regIp, regPort, 
                        localPort, args);
                    System.out.println("Hit return to terminate demo...");
                    try {
                            System.in.read();
                    } catch (IOException e) {
                            System.out.println(e.toString());
                    }
                    client.shutdown();
                    System.exit(0);
            }
    
            public CrnpClient(InetAddress regIpIn, int regPortIn, 
                int localPortIn, String []clArgs)
            {
                    try {
                            regIp = regIpIn;
                            regPort = regPortIn;
                            localPort = localPortIn;
                            regs = clArgs;
                            setupXmlProcessing();
                            createEvtRecepThr();
                            registerCallbacks();
                    } catch (Exception e) {
                            System.out.println(e.toString());
                            System.exit(1);
                    }
            }
    
            public void shutdown()
            {
                    try {
                            unregister();
                    } catch (Exception e) {
                            System.out.println(e);
                            System.exit(1);
                    }
            }
    
            private InetAddress regIp;
            private int regPort;
            private EventReceptionThread evtThr;
            private String regs[];
            public int localPort;
            public DocumentBuilderFactory dbf;
    }

    成員變數將稍後在本章中詳細論述。

Procedure如何剖析指令行引數

步驟

    若要剖析指令行引數,請參閱附錄 GCrnpClient.java 應用程式 中的程式碼。

Procedure如何定義事件接收執行緒

在程式碼中,您需要確定事件接收是在獨立的執行緒中執行的,以便應用程式可以在事件執行緒封鎖並等待事件回呼時繼續進行其他工作。


備註 –

設置 XML 將稍後在本章中論述。


步驟
  1. 在程式碼中,定義一個名為 EventReceptionThreadThread 子類別,其建立 ServerSocket 並等待事件到達通訊端的。

    在範例程式碼的此部分,事件既未被讀取,也未經過處理。讀取和處理事件將稍後在本章中論述。EventReceptionThread 將在萬用字元網際網路通訊協定位址上建立 ServerSocketEventReceptionThread 也將參照 CrnpClient 物件,以便 EventReceptionThread 可以傳送事件至 CrnpClient 物件,以進行處理。

    class EventReceptionThread extends Thread
    {
            public EventReceptionThread(CrnpClient clientIn) throws IOException
            {
                    client = clientIn;
                    listeningSock = new ServerSocket(client.localPort, 50,
                        InetAddress.getLocalHost());
            }
    
            public void run()
            {
                    try {
                            DocumentBuilder db = client.dbf.newDocumentBuilder();
                            db.setErrorHandler(new DefaultHandler());
    
                            while(true) {
                                    Socket sock = listeningSock.accept();
                                    // Construct event from the sock stream and process it
                                    sock.close();
                            }
                            // UNREACHABLE
    
                    } catch (Exception e) {
                            System.out.println(e);
                            System.exit(1);
                    }
            }
    
            /* private member variables */
            private ServerSocket listeningSock;
            private CrnpClient client;
    }
  2. 建構 createEvtRecepThr 物件。

    private void createEvtRecepThr() throws Exception
    {
            evtThr = new EventReceptionThread(this);
            evtThr.start();
    }

Procedure如何註冊與取消註冊回呼

註冊作業包含以下動作︰

步驟
  1. 建立實施前導邏輯的 Java 程式碼。

    以下範例程式碼將展示 CrnpClient 類別 (由 CrnpClient 建構子呼叫) 的 registerCallbacks 方法之實作。對 createRegistrationString()readRegistrationReply() 的呼叫將稍後在本章中詳細說明。

    regIpregPort 是由建構子設置的物件成員。

    private void registerCallbacks() throws Exception
    { 
            Socket sock = new Socket(regIp, regPort);
            String xmlStr = createRegistrationString();
            PrintStream ps = new 
                    PrintStream(sock.getOutputStream());
            ps.print(xmlStr);
            readRegistrationReply(sock.getInputStream();
            sock.close();
    }
  2. 實施 unregister 方法。

    此方法由 CrnpClientshutdown 方法呼叫。createUnregistrationString 的實作將稍後在本章中詳細說明。

    private void unregister() throws Exception
    {
            Socket sock = new Socket(regIp, regPort);
            String xmlStr = createUnregistrationString();
            PrintStream ps = new PrintStream(sock.getOutputStream());
            ps.print(xmlStr);
            readRegistrationReply(sock.getInputStream());
            sock.close();
    }

Procedure如何產生 XML

由於您已設置了應用程式的結構並寫入了所有網路程式碼,因此,您需要寫入用於產生並剖析 XML 的程式碼。由寫入產生 SC_CALLBACK_REG XML 註冊訊息的程式碼開始。

SC_CALLBACK_REG 訊息由註冊類型 (ADD_CLIENTREMOVE_CLIENTADD_EVENTSREMOVE_EVENTS),回呼連接埠和感興趣的事件清單組成。每個事件由類別與子類別組成,其後跟隨名稱與值對的清單。

在範例的此部分,您將寫入儲存註冊類型、回呼通訊埠及註冊事件清單的 CallbackReg 類別。此類別還可將自身串列化為 SC_CALLBACK_REG XML 訊息。

此類別使人感興趣的方法為 convertToXml 方法,該方法建立類別成員的 SC_CALLBACK_REG XML 訊息字串。http://java.sun.com/xml/jaxp/index.html 中的 JAXP 文件將更詳細地說明此方法中的程式碼。

將在以下範例程式碼中展示 Event 類別的實作。請注意,CallbackReg 類別使用用於儲存一個事件,並能夠將該事件轉換為 XML ElementEvent 類別。

步驟
  1. 建立實施前導邏輯的 Java 程式碼。

    class CallbackReg
    {
            public static final int ADD_CLIENT = 0;
            public static final int ADD_EVENTS = 1;
            public static final int REMOVE_EVENTS = 2;
            public static final int REMOVE_CLIENT = 3;
    
            public CallbackReg()
            {
                    port = null;
                    regType = null;
                    regEvents = new Vector();
            }
    
            public void setPort(String portIn)
            {
                    port = portIn;
            }
    
            public void setRegType(int regTypeIn)
            {
                    switch (regTypeIn) {
                    case ADD_CLIENT:
                            regType = "ADD_CLIENT";
                            break;
                    case ADD_EVENTS:
                            regType = "ADD_EVENTS";
                            break;
                    case REMOVE_CLIENT:
                            regType = "REMOVE_CLIENT";
                            break;
                    case REMOVE_EVENTS:
                            regType = "REMOVE_EVENTS";
                            break;
                    default:
                            System.out.println("Error, invalid regType " +
                                regTypeIn);
                            regType = "ADD_CLIENT";
                            break;
                    }
            }
    
            public void addRegEvent(Event regEvent)
            {
                    regEvents.add(regEvent);
            } 
    
            public String convertToXml()
            {
                    Document document = null;
                    DocumentBuilderFactory factory =
                        DocumentBuilderFactory.newInstance();
                    try {
                            DocumentBuilder builder = factory.newDocumentBuilder();
                            document = builder.newDocument(); 
                    } catch (ParserConfigurationException pce) {
                            // Parser with specified options can't be built
                            pce.printStackTrace();
                            System.exit(1);
                    }
    
                    // Create the root element
                    Element root = (Element) document.createElement("SC_CALLBACK_REG");
    
                    // Add the attributes
                    root.setAttribute("VERSION", "1.0");
                    root.setAttribute("PORT", port);
                    root.setAttribute("regType", regType);
    
                    // Add the events
                    for (int i = 0; i < regEvents.size(); i++) {
                            Event tempEvent = (Event)
                                (regEvents.elementAt(i));
                            root.appendChild(tempEvent.createXmlElement(document));
                    }
                    document.appendChild(root);
    
                    // Convert the whole thing to a string
                    DOMSource domSource = new DOMSource(document);
                    StringWriter strWrite = new StringWriter();
                    StreamResult streamResult = new StreamResult(strWrite);
                    TransformerFactory tf = TransformerFactory.newInstance();
                    try {
                            Transformer transformer = tf.newTransformer();
                            transformer.transform(domSource, streamResult);
                    } catch (TransformerException e) {
                            System.out.println(e.toString());
                            return ("");
                    }
                    return (strWrite.toString());
            }
    
            private String port;
            private String regType;
            private Vector regEvents;
    }
  2. 實作 EventNVPair 類別。

    請注意,CallbackReg 類別使用 Event 類別 (其使用 NVPair 類別)。

    class Event
    {
    
            public Event()
            {
                    regClass = regSubclass = null;
                    nvpairs = new Vector();
            }
    
            public void setClass(String classIn)
            {
                    regClass = classIn;
            }
    
            public void setSubclass(String subclassIn)
            {
                    regSubclass = subclassIn;
            }
    
            public void addNvpair(NVPair nvpair)
            {
                    nvpairs.add(nvpair);
            }
    
            public Element createXmlElement(Document doc)
            {
                    Element event = (Element)
                        doc.createElement("SC_EVENT_REG");
                    event.setAttribute("CLASS", regClass);
                    if (regSubclass != null) {
                            event.setAttribute("SUBCLASS", regSubclass);
                    }
                    for (int i = 0; i < nvpairs.size(); i++) {
                         NVPair tempNv = (NVPair)
                             (nvpairs.elementAt(i));
                         event.appendChild(tempNv.createXmlElement(doc));
                    }
                    return (event);
            }
    
            private String regClass, regSubclass;
            private Vector nvpairs;
    }
    
    class NVPair
    {
            public NVPair()
            {
                    name = value = null;
            }
    
            public void setName(String nameIn)
            {
                    name = nameIn;
            }
    
            public void setValue(String valueIn)
            {
                    value = valueIn;
            }
    
            public Element createXmlElement(Document doc)
            {
                    Element nvpair = (Element)
                        doc.createElement("NVPAIR");
                    Element eName = doc.createElement("NAME");
                    Node nameData = doc.createCDATASection(name);
                    eName.appendChild(nameData);
                    nvpair.appendChild(eName);
                    Element eValue = doc.createElement("VALUE");
                    Node valueData = doc.createCDATASection(value);
                    eValue.appendChild(valueData);
                    nvpair.appendChild(eValue);
    
                    return (nvpair);
            }
    
            private String name, value;
    }

Procedure如何建立註冊和取消註冊訊息

由於您已建立了產生 XML 訊息的輔助程式類別,因此您可以寫入 createRegistrationString 方法的實作。此方法由 registerCallbacks 方法呼叫,有關此方法的說明位於如何註冊與取消註冊回呼

createRegistrationString 建構 CallbackReg 物件,並設定其註冊類型與通訊埠。然後,透過使用 createAllEventcreateMembershipEventcreateRgEventcreateREvent 輔助程式方法,createRegistrationString 將建構多種事件。在建立 CallbackReg 物件之後,便會將每個事件加入該物件。最後,createRegistrationStringCallbackReg 物件呼叫 convertToXml 方法,以擷取 String 形式的 XML 訊息。

請注意,regs 成員變數會儲存使用者為應用程式提供的指令行引數。第五個引數與後續引數指定應用程式應該註冊的事件。第四個引數指定註冊的類型,但在此範例中忽略。附錄 GCrnpClient.java 應用程式 中的完整程式碼將展示如何使用第四個引數。

步驟
  1. 建立實施前導邏輯的 Java 程式碼。

    private String createRegistrationString() throws Exception
    {
            CallbackReg cbReg = new CallbackReg();
            cbReg.setPort("" + localPort);
    
            cbReg.setRegType(CallbackReg.ADD_CLIENT);
    
            // add the events
            for (int i = 4; i < regs.length; i++) {
                    if (regs[i].equals("M")) {
                            cbReg.addRegEvent(createMembershipEvent());
                    } else if (regs[i].equals("A")) {
                            cbReg.addRegEvent(createAllEvent());
                    } else if (regs[i].substring(0,2).equals("RG")) {
                            cbReg.addRegEvent(createRgEvent(regs[i].substring(3)));
                    } else if (regs[i].substring(0,1).equals("R")) {
                            cbReg.addRegEvent(createREvent(regs[i].substring(2))); 
                    }
            }
    
            String xmlStr = cbReg.convertToXml();
            return (xmlStr);
    }
    
    private Event createAllEvent()
    {
            Event allEvent = new Event();
            allEvent.setClass("EC_Cluster");
            return (allEvent);
    }
    
    private Event createMembershipEvent()
    {
            Event membershipEvent = new Event();
            membershipEvent.setClass("EC_Cluster");
            membershipEvent.setSubclass("ESC_cluster_membership");
            return (membershipEvent);
    }
    
    private Event createRgEvent(String rgname)
    {
            Event rgStateEvent = new Event();
            rgStateEvent.setClass("EC_Cluster");
            rgStateEvent.setSubclass("ESC_cluster_rg_state");
    
            NVPair rgNvpair = new NVPair();
            rgNvpair.setName("rg_name");
            rgNvpair.setValue(rgname);
            rgStateEvent.addNvpair(rgNvpair);
    
            return (rgStateEvent);
    }
    
    private Event createREvent(String rname)
    {
            Event rStateEvent = new Event();
            rStateEvent.setClass("EC_Cluster");
            rStateEvent.setSubclass("ESC_cluster_r_state");
    
            NVPair rNvpair = new NVPair();
            rNvpair.setName("r_name");
            rNvpair.setValue(rname);
            rStateEvent.addNvpair(rNvpair);
    
            return (rStateEvent);
    }
  2. 建立取消註冊字串。

    由於您無需提供事件,因此建立取消註冊字串比建立註冊字串更容易。

    private String createUnregistrationString() throws Exception
    {
            CallbackReg cbReg = new CallbackReg();
            cbReg.setPort("" + localPort);
            cbReg.setRegType(CallbackReg.REMOVE_CLIENT);
            String xmlStr = cbReg.convertToXml();
            return (xmlStr);
    }

Procedure如何設置 XML 剖析器

您現在已經為應用程式建立了網路程式碼與 XML 產生程式碼。CrnpClient 建構子將呼叫 setupXmlProcessing 方法。此方法將建立 DocumentBuilderFactory 物件並在該物件上設定多種剖析特性。JAXP 文件將更詳細地說明此方法。請參閱 http://java.sun.com/xml/jaxp/index.html

步驟

    建立實施前導邏輯的 Java 程式碼。

    private void setupXmlProcessing() throws Exception
    {
            dbf = DocumentBuilderFactory.newInstance();
    
            // We don't need to bother validating
            dbf.setValidating(false);
            dbf.setExpandEntityReferences(false);
    
            // We want to ignore comments and whitespace
            dbf.setIgnoringComments(true);
            dbf.setIgnoringElementContentWhitespace(true);
    
            // Coalesce CDATA sections into TEXT nodes.
            dbf.setCoalescing(true);
    }

Procedure如何剖析註冊回覆

若要剖析 CRNP 伺服器應註冊或取消註冊訊息而傳送的 SC_REPLY XML 訊息,您需要 RegReply 輔助程式類別。您可以從 XML 文件建構此類別。此類別為狀況碼與狀況訊息提供 accessor。若要剖析伺服器的 XML 串流,您需要建立新的 XML 文件,並使用該文件的剖析方法。http://java.sun.com/xml/jaxp/index.html 中的 JAXP 文件將更詳細地說明此方法。

步驟
  1. 建立實施前導邏輯的 Java 程式碼。

    請注意,readRegistrationReply 方法使用新的 RegReply 類別。

    private void readRegistrationReply(InputStream stream) throws Exception
    {
            // Create the document builder
            DocumentBuilder db = dbf.newDocumentBuilder();
            db.setErrorHandler(new DefaultHandler());
    
            //parse the input file
            Document doc = db.parse(stream);
    
            RegReply reply = new RegReply(doc);
            reply.print(System.out);
    }
  2. 實施 RegReply 類別。

    請注意,retrieveValues 方法在 XML 文件的 DOM 樹狀結構中行走,然後取出狀況碼與狀況訊息。http://java.sun.com/xml/jaxp/index.html 中的 JAXP 文件包含更多詳細資訊。

    class RegReply
    {
            public RegReply(Document doc)
            {
                    retrieveValues(doc);
            }
    
            public String getStatusCode()
            {
                    return (statusCode);
            }
    
            public String getStatusMsg()
            {
                    return (statusMsg);
            }
            public void print(PrintStream out)
            {
                    out.println(statusCode + ": " +
                        (statusMsg != null ? statusMsg : ""));
            }
    
            private void retrieveValues(Document doc)
            {
                    Node n;
                    NodeList nl;
                    String nodeName;
    
                    // Find the SC_REPLY element.
                    nl = doc.getElementsByTagName("SC_REPLY");
                    if (nl.getLength() != 1) {
                            System.out.println("Error in parsing: can't find "
                                + "SC_REPLY node.");
                            return;
                    }
    
                    n = nl.item(0);
    
                    // Retrieve the value of the statusCode attribute
                    statusCode = ((Element)n).getAttribute("STATUS_CODE");
    
                    // Find the SC_STATUS_MSG element
                    nl = ((Element)n).getElementsByTagName("SC_STATUS_MSG");
                    if (nl.getLength() != 1) {
                            System.out.println("Error in parsing: can't find "
                                + "SC_STATUS_MSG node.");
                            return;
                    }
                    // Get the TEXT section, if there is one.
                    n = nl.item(0).getFirstChild();
                    if (n == null || n.getNodeType() != Node.TEXT_NODE) {
                    // Not an error if there isn't one, so we just silently return.
                            return;
                    }
    
                    // Retrieve the value
                    statusMsg = n.getNodeValue();
            }
    
            private String statusCode;
            private String statusMsg;
    }

Procedure如何剖析回呼事件

最後一個步驟是剖析與處理實際的回呼事件。若要輔助此作業,您可修改在 如何產生 XML 中建立的 Event 類別,以便此類別可以從 XML 文件建構 Event,並建立 XML Element。此變更需要附加的建構子 (可執行 XML 文件)、retrieveValues 方法、兩個成員變數 (vendorpublisher) 之和、所有欄位的存取方法以及輸出方法。

步驟
  1. 建立實施前導邏輯的 Java 程式碼。

    請注意,此程式碼與如何剖析註冊回覆中說明的 RegReply 類別的程式碼相似。

    public Event(Document doc)
            {
                    nvpairs = new Vector();
                    retrieveValues(doc);
            }
            public void print(PrintStream out)
            {
                    out.println("\tCLASS=" + regClass);
                    out.println("\tSUBCLASS=" + regSubclass);
                    out.println("\tVENDOR=" + vendor);
                    out.println("\tPUBLISHER=" + publisher);
                    for (int i = 0; i < nvpairs.size(); i++) {
                            NVPair tempNv = (NVPair)
                                (nvpairs.elementAt(i));
                            out.print("\t\t");
                            tempNv.print(out);
                    }
            }
    
            private void retrieveValues(Document doc)
            {
                    Node n;
                    NodeList nl;
                    String nodeName;
    
                    // Find the SC_EVENT element.
                    nl = doc.getElementsByTagName("SC_EVENT");
                    if (nl.getLength() != 1) {
                       System.out.println("Error in parsing: can't find "
                           + "SC_EVENT node.");
                       return;
                    }
    
                    n = nl.item(0);
    
                    //
                    // Retrieve the values of the CLASS, SUBCLASS,
                    // VENDOR and PUBLISHER attributes.
                    //
                    regClass = ((Element)n).getAttribute("CLASS");
                    regSubclass = ((Element)n).getAttribute("SUBCLASS");
                    publisher = ((Element)n).getAttribute("PUBLISHER");
                    vendor = ((Element)n).getAttribute("VENDOR");
    
                    // Retrieve all the nv pairs
                    for (Node child = n.getFirstChild(); child != null;
                        child = child.getNextSibling())
                    {
                           nvpairs.add(new NVPair((Element)child));
                    }
            }
    
            public String getRegClass()
            {
                    return (regClass);
            }
    
            public String getSubclass()
            {
                    return (regSubclass);
            }
    
            public String getVendor()
            {
                    return (vendor);
            }
    
            public String getPublisher()
            {
                    return (publisher);
            }
    
            public Vector getNvpairs()
            {
                    return (nvpairs);
            }
    
            private String vendor, publisher;
  2. 實作附加建構子和支援 XML 剖析的 NVPair 類別之方法。

    對顯示在步驟 1 中的 Event 類別所做的變更,需與對 NVPair 類別所做變更相似。

    public NVPair(Element elem)
            {
                    retrieveValues(elem);
            }
            public void print(PrintStream out)
            {
                    out.println("NAME=" + name + " VALUE=" + value);
            }
            private void retrieveValues(Element elem)
            {
                    Node n;
                    NodeList nl;
                    String nodeName;
    
                    // Find the NAME element
                    nl = elem.getElementsByTagName("NAME");
                    if (nl.getLength() != 1) {
                       System.out.println("Error in parsing: can't find "
                           + "NAME node.");
                       return;
                    }
                    // Get the TEXT section
                    n = nl.item(0).getFirstChild();
                    if (n == null || n.getNodeType() != Node.TEXT_NODE) {
                       System.out.println("Error in parsing: can't find "
                           + "TEXT section.");
                       return;
                    }
    
                    // Retrieve the value
                    name = n.getNodeValue();
    
                    // Now get the value element
                    nl = elem.getElementsByTagName("VALUE");
                    if (nl.getLength() != 1) {
                       System.out.println("Error in parsing: can't find "
                           + "VALUE node.");
                       return;
                    }
                    // Get the TEXT section
                    n = nl.item(0).getFirstChild();
                    if (n == null || n.getNodeType() != Node.TEXT_NODE) {
                    System.out.println("Error in parsing: can't find "
                                + "TEXT section.");
                            return;
                    }
    
                    // Retrieve the value
                    value = n.getNodeValue();
                    }
    
            public String getName()
            {
                    return (name);
            }
    
            public String getValue()
            {
                    return (value);
            }
    }
  3. 實作 EventReceptionThread (其等待事件回呼) 中的 while 迴路。

    如何定義事件接收執行緒說明 EventReceptionThread

    while(true) {
                    Socket sock = listeningSock.accept();
                    Document doc = db.parse(sock.getInputStream());
                    Event event = new Event(doc);
                    client.processEvent(event);
                    sock.close();
            }

Procedure如何執行應用程式

步驟
  1. 成為超級使用者,或者假定一個對等身份。

  2. 執行應用程式。


    # java CrnpClient crnpHost crnpPort localPort ...
    

    附錄 GCrnpClient.java 應用程式 列出了 CrnpClient 應用程式的完整程式碼。