軽くて気楽にNIOを書く(改良版)

15691 ワード

既存のNIOモジュールを改良する、イベント処理インタフェースを追加し、以下に、実装例を参照する.
準備条件:インタフェースの紹介
1:サーバリスナーは、リモート接続またはフラクチャイベントをキャプチャし、処理するために使用されます.インタフェースの定義は次のとおりです.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
 
/*
*Copyright (c) jmin Organization. All rights reserved.
*/
package org.jmin.j2ee.kernel.net;
 
/**
 * A listener run in service side and catch connection request event from
 * client.
 *
 * @author Chris Liao
 */
 
public interface ServerListener extends NetEventListener {
 
  /**
   * When a connection requst arrives,this method will run.
   */
  public void onConnect(ConnectEvent event);
 
  /**
   * Method run after acceptance in server side.
   */
  public void onConnected(ConnectedEvent event);
 
  /**
   * Method run after remote host close connection.
   */
  public void onClosed(DisconnectEvent event);
 
}

2:コネクタのListenerコネクタのListenerコネクタは、読み書きイベントなどのコネクタで発生する読み書きイベントを処理するために使用されます.インタフェースは次のとおりです.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
  
/*
*Copyright (c) jmin Organization. All rights reserved.
*/
package org.jmin.j2ee.kernel.net;
 
/**
 * A communication event listener
 *
 * @author Chris Liao
 */
 
public interface NetConnectorListener extends NetEventListener {
 
  /**
   * Connection to remote host is stable
   */
  public void onConnected(ConnectedEvent event);
 
  /**
   * Read data from remote host
   */
  public void onRead(ReadEvent event);
 
  /**
   * Write data to remote host
   */
  public void onWrite(WriteEvent event);
 
  /**
   * Remote host close connection
   */
  public void onClosed(DisconnectEvent event);
 
  /**
   * When errors occur during communication
   */
  public void onError(ErrorEvent event);
 
}

次に、上記インタフェースに基づいて、NIOリファレンス実装例を記述する.
ステップ1:サーバListener実装を作成します.次のようにします.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
/*
*Copyright (c) jmin Organization. All rights reserved.
*/
package org.jmin.j2ee.kernel.net.nio.test;
 
import org.jmin.j2ee.kernel.net.ConnectEvent;
import org.jmin.j2ee.kernel.net.ConnectedEvent;
import org.jmin.j2ee.kernel.net.DisconnectEvent;
import org.jmin.j2ee.kernel.net.ServerListener;
import org.jmin.j2ee.kernel.net.nio.NIOConnector;
 
/**
 * A sample implementation of server listener interface and action by event.
 * This listener act on server channel.
 *
 * @author Chris Liao
 */
 
public class NIOServerListener implements ServerListener {
 
  /**
   * Method to handle a event represents request from remote host
   *
   * @param event
   */
  public void onConnect(ConnectEvent event){
 
    /**
     * cast event source to a connector
     */
    NIOConnector con = (NIOConnector)event.getSource();
 
    /**
     * print request
     */
    System.out.println("Find a connection request from: " + con.getRemoteHost());
  }
 
  /**
   * If the comming connection is accepted by server, a notification event will
   * be sent out.
   *
   * @param event
   */
  public void onConnected(ConnectedEvent event){
 
    /**
     * cast event source to a connector
     */
    NIOConnector con = (NIOConnector)event.getSource();
 
    /**
     * print request
     */
    System.out.println("Accepted a connection request from: " + con.getRemoteHost());
  }
 
  /**
   * If remote host close connection to server, a event will be sent and handled
   * by this method.
   *
   * @param event
   */
  public void onClosed(DisconnectEvent event){
 
    /**
     * cast event source to a connector
     */
    NIOConnector con = (NIOConnector)event.getSource();
 
    /**
     * print a hint message
     */
    System.out.println("Connection to host[" + con.getRemoteHost() +"] is closed from server");
  }
}
 

ステップ2:Serverイニシエータの作成
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
 
/*
*Copyright (c) jmin Organization. All rights reserved.
*/
package org.jmin.j2ee.kernel.net.nio.test;
 
import java.io.IOException;
 
import org.jmin.j2ee.kernel.net.nio.ServerCluster;
 
/**
 * Test sample to build a socket server based on NIO and don't care more detail.
 *
 * @author chris
 */
 
public class NIOServer {
 
  /**
   * Entrance method to build a server.If get familiar with nio, it is easy to be
   * catched.
   */
  public static void main(String args[]) throws IOException {
 
    /**
     * Cluster object works as a server collection manager,some servers can be open
     * in it.Before useful operation,<method>open</method>must be invoked to create
     * a cluster instance.
     */
    ServerCluster cluster = ServerCluster.open();
 
    /**
     * Create a server listener
     */
    NIOServerListener serverListener = new NIOServerListener();
 
    /**
     * Call<method>openServer</method>to create a socket server,two necessary
     * arguments are applied here: server port and message lister class.
     *
     * We can assume that every server can handle matched messages from clients,
     * this listener class is extended from super <class>org.jmin.j2ee.kernel.Listener</class>,
     * of course,you can define sub implementation based on the class.
     */
    cluster.openServer(9988,serverListener,NIOConnectionListener.class);
 
    /**
     * Print a successful creation message on console.
     */
    System.out.println("A nio server run on port: "+ 9988);
 
    /**
     * Create a synchronized object to block the main thread and make the server kept running.
     */
    Object obj = new Object();
    try {
      synchronized (obj) {
        obj.wait();
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

ステップ3:接続リスナー実装の作成
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
 
/*
*Copyright (c) jmin Organization. All rights reserved.
*/
package org.jmin.j2ee.kernel.net.nio.test;
 
import org.jmin.j2ee.kernel.net.NetConnectorListener;
import org.jmin.j2ee.kernel.net.DisconnectEvent;
import org.jmin.j2ee.kernel.net.ErrorEvent;
import org.jmin.j2ee.kernel.net.ReadEvent;
import org.jmin.j2ee.kernel.net.WriteEvent;
import org.jmin.j2ee.kernel.net.ConnectedEvent;
import org.jmin.j2ee.kernel.net.nio.NIOConnector;
 
/**
 * A reference implementation of listener interface on net connector.
 * This object can handle some events from net connector, for example:
 * connection event, read event, write event and so on.
 *
 * Class instances work in client side and server side.
 *
 * @author Chris Liao
 */
 
public class NIOConnectionListener implements NetConnectorListener {
 
  /**
   * When connection to remote host is stable, a connection event will be published,
   * and catched by this method.
   */
  public void onConnected(ConnectedEvent event){
 
    /**
     * cast event source to a connector
     */
    NIOConnector con = (NIOConnector)event.getSource();
 
    /**
     * print a hint message
     */
    System.out.println("Connection to host[" + con.getRemoteHost() +"] is stable");
  }
 
  /**
   * When some data has been read from remote host,then a read event is sent out.
   * This method is used to handle the event,some detailed logic can be added here.
   */
  public void onRead(ReadEvent event) {
 
    /**
     * get a byte array from event object
     */
    byte[] data = event.getData();
 
    /**
     * cast event source to a connector
     */
    NIOConnector con = (NIOConnector)event.getSource();
 
    /**
     * print message on console
     */
    System.out.println("Read a meessage: " + new String(data));
 
    /**
     * send the data to remote, in fact the byte data will stored in temp pool
     * util ready to be sent.
     */
    con.write(data);
  }
 
  /**
   * When a connector associated with the current listener send a message to remote,
   * then publish a event as notification.
   */
  public void onWrite(WriteEvent event) {
    byte[] data = event.getData();
    System.out.println("Send a message: " + new String(data));
  }
 
  /**
   * When remote host close connection, a event will be published.
   *
   * @param event
   */
  public void onClosed(DisconnectEvent event) {
 
    /**
     * cast event source to a connector
     */
    NIOConnector con = (NIOConnector)event.getSource();
 
    /**
     * print a hint message
     */
    System.out.println("Connection to host[" + con.getRemoteHost() +"] is closed");
  }
 
  /**
   * When a error cause during communication,publish a error event
   *
   * @param event
   */
  public void onError(ErrorEvent event) {
 
    /**
     * get the cuase of error
     */
    Throwable cause = event.getCause();
 
    /**
     * Print the cause of error
     */
    System.out.println("Catch a error: " + cause.getMessage());
  }
}

このクラスは、サーバとClientの両端に適用するが、具体的には、サーバとClient側の実装を別々に記述することができ、以上のコードは参照に供する.
ステップ4:クライアントのテストコードの作成
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
/*
*Copyright (c) jmin Organization. All rights reserved.
*/
package org.jmin.j2ee.kernel.net.nio.test;
 
import java.io.IOException;
 
import org.jmin.j2ee.kernel.net.nio.NIOConnector;
import org.jmin.j2ee.kernel.net.nio.NIOConnectorCluster;
 
/**
 * Test sample to show that how to build a nio client.
 *
 * @author Chris Liao
 */
 
public class NIOClient {
 
  /**
   * Main method to run a nio client.
   *
   */
  public static void main(String args[]) throws IOException {
 
    /**
     * Call static method from ConnectionCluster class to build its a instance,
     * this action is similar with nio.
     */
    NIOConnectorCluster cluster = NIOConnectorCluster.open();
 
    /**
     * Build a connection to remote host with threa parameters
     *
     * @arg remote host
     * @arg remote port
     * @arg message listener
     *
     * Message listener is extended from<class>org.jmin.j2ee.kernel.Listener</class>
     * You can define yourself message listeners for it.
     */
    NIOConnector con = cluster.connect("localhost", 9988,new NIOConnectionListener());
 
    /**
     * Send a message to the remote host.
     */
    con.write("I am a Chinese".getBytes());
 
    /**
     * synchronized objec to block main thread.
     */
    Object obj = new Object();
    try {
      synchronized (obj) {
        obj.wait();
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

以上の4つのステップを経て、NIO通信を確立するすべてのプロセスを完了しました.これで、彼らをコンパイルし、ServerとClientをそれぞれ実行して実行効果を見ることができます.正しく動作するとConsoleで「Receive data:I am a Chinese」が頻繁に見られます