1
package sample.nio;
2
3
import java.io.IOException;
4
import java.net.*;
5
import java.nio.ByteBuffer;
6
import java.nio.channels.*;
7
8
/**//**
9
* <p>Title: </p>
10
*
11
* <p>Description: </p>
12
*
13
* <p>Copyright: Copyright (c) 2005</p>
14
*
15
* <p>Company: </p>
16
*
17
* @author George Hill
18
* @version 1.0
19
*/
20
21
public class Client1
{
22
23
private static final String EXIT = "EXIT";
24
25
private InetAddress host;
26
private int port;
27
28
public Client1(InetAddress host, int port)
{
29
this.host = host;
30
this.port = port;
31
}
32
33
public void startClient() throws IOException
{
34
// 創建SocketChannel
35
SocketChannel channel = SocketChannel.open(new InetSocketAddress(host, port));
36
channel.configureBlocking(false);
37
38
int read = 0;
39
ByteBuffer buffer = ByteBuffer.allocate(1024);
40
41
System.out.println("Client Start");
42
43
int i = 0;
44
while ((read = channel.read(buffer)) != -1)
{
45
if (read == 0)
{
46
System.out.println(i++ + " read a null string");
47
try
{
48
Thread.sleep(1000);
49
} catch (InterruptedException ie)
{
50
}
51
}
52
53
buffer.flip();
54
byte[] array = new byte[read];
55
buffer.get(array);
56
String s = new String(array);
57
System.out.print(s);
58
buffer.clear();
59
60
if (s.endsWith(EXIT))
{
61
System.out.println();
62
}
63
}
64
65
channel.close();
66
System.out.println("Client Stop");
67
}
68
69
public static void main(String[] args) throws Exception
{
70
Client1 client = new Client1(InetAddress.getLocalHost(), 5000);
71
client.startClient();
72
}
73
}
74

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

這個客戶端程序類似于傳統的IO客戶端程序,只是在36行設定為非阻塞,如果這里設置成true,那么和傳統的IO實現沒有什么很大的區別。不過,這個程序有一個很大的問題,由于在36行設置成非阻塞的IO,所在在讀的時候是不會阻塞的,那么在44行的while循環會不停的執行,可以看到輸出很多“read a null string”。如果在這里不強制進行線程睡眠,CPU資源很快就耗盡。
改進的方法是使用Selector,下面是另外一個客戶端的實現:
1
package sample.nio;
2
3
import java.io.IOException;
4
import java.net.*;
5
import java.nio.ByteBuffer;
6
import java.nio.channels.*;
7
import java.util.*;
8
9
/**//**
10
* <p>Title: </p>
11
*
12
* <p>Description: </p>
13
*
14
* <p>Copyright: Copyright (c) 2005</p>
15
*
16
* <p>Company: </p>
17
*
18
* @author George Hill
19
* @version 1.0
20
*/
21
22
public class Client2
{
23
24
private static final String EXIT = "EXIT";
25
26
private InetAddress host;
27
private int port;
28
29
public Client2(InetAddress host, int port)
{
30
this.host = host;
31
this.port = port;
32
}
33
34
public void startClient() throws IOException
{
35
// 創建SocketChannel
36
SocketChannel channel = SocketChannel.open(new InetSocketAddress(host, port));
37
channel.configureBlocking(false);
38
39
// 創建Selector
40
Selector selector = Selector.open();
41
// 向Selector注冊我們需要的READ事件
42
SelectionKey skey = channel.register(selector, SelectionKey.OP_READ);
43
44
boolean stop = false;
45
int n = 0;
46
int read = 0;
47
ByteBuffer buffer = ByteBuffer.allocate(1024);
48
49
System.out.println("Client Start");
50
51
// 輪詢
52
while (!stop)
{
53
// 獲取Selector返回的時間值
54
n = selector.select();
55
56
// 當傳回的值大于0事,讀時間發生了
57
if (n > 0)
{
58
Set set = selector.selectedKeys();
59
Iterator it = set.iterator();
60
61
while (it.hasNext())
{
62
skey = (SelectionKey) it.next();
63
it.remove();
64
65
if (skey.isReadable())
{
66
SocketChannel sc = (SocketChannel) skey.channel();
67
68
while ((read = sc.read(buffer)) != -1)
{
69
if (read == 0)
70
break;
71
72
buffer.flip();
73
byte[] array = new byte[read];
74
buffer.get(array);
75
String s = new String(array);
76
System.out.print(s);
77
buffer.clear();
78
79
if (s.endsWith(EXIT))
{
80
stop = true;
81
System.out.println();
82
}
83
}
84
}
85
}
86
}
87
}
88
89
channel.close();
90
System.out.println("Client Stop");
91
}
92
93
public static void main(String[] args) throws Exception
{
94
Client2 client = new Client2(InetAddress.getLocalHost(), 5000);
95
client.startClient();
96
}
97
}
98

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

由于使用了Selector,程序只有當注冊的事件發生時,才會繼續執行,所以在這里不需要再用線程睡眠的方式去釋放CPU資源。