客户端可以给服务端发消息,服务端也可以给客户端反馈。
注释最好清晰点,说明selector,channel,buffer的用法的实例。谢谢各位大牛,小弟刚学nio,c/s通信,希望给一个易懂的例子,谢谢大家。!:)
注释最好清晰点,说明selector,channel,buffer的用法的实例。谢谢各位大牛,小弟刚学nio,c/s通信,希望给一个易懂的例子,谢谢大家。!:)
解决方案 »
- JDBC连接mysql速度突然变得奇慢!
- 请教rs.getInt( );的问题
- Spring Struts+Hibernate Action不被执行,提示Servlet action is not available
- 请高手品帖:从分页模板浅谈3大框架遗漏的东西
- tomcat的奇怪问题
- jsp页面中实现动态显示问题?请帮助,高分相赠!
- 求:O'Reilly Java Servlet Programming, 可以发到我的信箱
- 关于tomcat
- 再次请教如何在ultra dev里连接数据库!
- 关于Session对象属性的问题
- 著名的空指针异常啊 各位高手啊 挑挑这个空指针啊 点击添加按钮进入dispacherAction的add方法 谢谢了啊!!!
- ssh1整合 删除一条记录 报数字格式化异常
29.
30.package helloweenpad;
31.
32.import java.io.FileInputStream;
33.import java.net.InetSocketAddress;
34.import java.net.Socket;
35.import java.nio.ByteBuffer;
36.import java.nio.CharBuffer;
37.import java.nio.channels.SelectionKey;
38.import java.nio.channels.Selector;
39.import java.nio.channels.ServerSocketChannel;
40.import java.nio.channels.SocketChannel;
41.import java.nio.charset.Charset;
42.import java.nio.charset.CharsetDecoder;
43.import java.nio.charset.CharsetEncoder;
44.import java.util.Iterator;
45.import java.util.Properties;
46.
47.public class MyFirstNIOServer {
48.
49.public static final int PORT = 12315;
50.
51.protected Selector selector;
52.protected Charset charset = Charset.forName("UTF-8");
53.protected CharsetEncoder charsetEncoder = charset.newEncoder();
54.protected CharsetDecoder charsetDecoder = charset.newDecoder();
55.
56.protected Properties talks = new Properties();
57.
58.int clientCount;
59.
60.public MyFirstNIOServer() throws Exception {
61.
62.talks.load(new FileInputStream("E:\\talk.properties"));
63.
64.selector = Selector.open();
65.
66.ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
67.serverSocketChannel.socket().bind(new InetSocketAddress(PORT)); // port
68.serverSocketChannel.configureBlocking(false);
69.serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);// register
70.
71.p("Server localhost:" + PORT + " started. waiting for clients. ");
72.
73.while (true) {
74. // selector 线程。select() 会阻塞,直到有客户端连接,或者有消息读入
75. selector.select();
76. Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
77. while (iterator.hasNext()) {
78.
79. SelectionKey selectionKey = iterator.next();
80. iterator.remove(); // 删除此消息
81.
82. // 并在当前线程内处理。(为了高效,一般会在另一个线程中处理此消息,例如使用线程池等)
83. handleSelectionKey(selectionKey);
84. }
85.}
86.
87.}
88.
89.public void handleSelectionKey(SelectionKey selectionKey) throws Exception {
90.
91.if (selectionKey.isAcceptable()) {
92.
93. // 有客户端进来
94. clientCount++;
95.
96. ServerSocketChannel serverSocketChannel = (ServerSocketChannel) selectionKey.channel();
97. SocketChannel socketChannel = serverSocketChannel.accept();
98. socketChannel.configureBlocking(false);
99. Socket socket = socketChannel.socket();
100.
101. // 立即注册一个 OP_READ 的SelectionKey, 接收客户端的消息
102. SelectionKey key = socketChannel.register(selector, SelectionKey.OP_READ);
103. key.attach("第 " + clientCount + " 个客户端 [" + socket.getRemoteSocketAddress() + "]: ");
104.
105. p(key.attachment() + "\t[connected] =========================================");
106.
107.} else if (selectionKey.isReadable()) {
108.
109. // 有消息进来
110.
111. ByteBuffer byteBuffer = ByteBuffer.allocate(100);
112. SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
113.
114. try {
115. int len = socketChannel.read(byteBuffer);
116.
117. // 如果len>0,表示有输入。如果len==0, 表示输入结束。需要关闭 socketChannel
118. if (len > 0) {
119.
120. byteBuffer.flip();
121. String msg = charsetDecoder.decode(byteBuffer).toString();
122.
123. // 根据客户端的消息,查找到对应的输出
124. String newMsg = talks.getProperty(msg);
125. if (newMsg == null)
126. newMsg = "Sorry? I don't understand your message. ";
127.
128. // UTF-8 格式输出到客户端,并输出一个'n'
129.
130. socketChannel.write(charsetEncoder.encode(CharBuffer.wrap(newMsg + "\n")));
131. p(selectionKey.attachment() + "\t[recieved]: " + msg + " ----->\t[send]: " + newMsg);
132.
133. } else {
134. // 输入结束,关闭 socketChannel
135. p(selectionKey.attachment() + "read finished. close socketChannel. ");
136. socketChannel.close();
137. }
138.
139. } catch (Exception e) {
140.
141. // 如果read抛出异常,表示连接异常中断,需要关闭 socketChannel
142. e.printStackTrace();
143.
144. p(selectionKey.attachment() + "socket closed? ");
145. socketChannel.close();
146. }
147.
148.} else if (selectionKey.isWritable()) {
149. p(selectionKey.attachment() + "TODO: isWritable() ???????????????????????????? ");
150.} else if (selectionKey.isConnectable()) {
151. p(selectionKey.attachment() + "TODO: isConnectable() ????????????????????????? ");
152.} else {
153. p(selectionKey.attachment() + "TODO: else. ");
154.}
155.
156.}
157.
158.public static void p(Object object) {
159.System.out.println(object);
160.}
161.
162.public static void main(String[] args) throws Exception {
163.new MyFirstNIOServer();
164.}
165.
166.}
//add by 郄永军
package helloweenpad;
171.
172.import java.io.BufferedReader;
173.import java.io.FileInputStream;
174.import java.io.InputStream;
175.import java.io.InputStreamReader;
176.import java.io.OutputStream;
177.import java.net.Socket;
178.import java.util.Properties;
179.import java.util.Random;
180.
181.public class MyFirstNIOClientTest extends Thread {
182.
183.public static final String HOST = "localhost";
184.public static final int PORT = 12315;
185.
186.boolean exist = false;
187.
188.Properties talks = new Properties();
189.Random random = new Random();
190.String[] keys;
191.
192.int messageCount = 0;
193.
194.public void run() {
195.
196.try {
197.
198. // 对话内容
199. talks.load(new FileInputStream("E:\\talk.properties"));
200.
201. // 客户端发送 "=" 左边的内容
202. keys = new String[talks.size()];
203. talks.keySet().toArray(keys);
204.
205. Socket socket = new Socket(HOST, PORT);
206.
207. OutputStream ous = socket.getOutputStream();
208. InputStream ins = socket.getInputStream();
209.
210. // 接收线程,接收服务器的回应
211. RecieverThread reciever = new RecieverThread(ins);
212. reciever.start();
213.
214. while (!exist) {
215.
216. messageCount++;
217.
218. // 选择一个随机消息
219. String msg = chooseMessage();
220.
221. synchronized (ins) {
222.
223. // 发送给服务器端
224. ous.write(msg.getBytes("UTF-8"));
225.
226. System.out.println("[send]\t" + messageCount + ": " + msg);
227.
228. // 然后等待接收线程
229. ins.wait();
230. }
231.
232. if (msg.equals("Bye")) {
233. break;
234. }
235. }
236.
237. ins.close();
238. ous.close();
239. socket.close();
240.
241.} catch (Exception e) {
242. e.printStackTrace();
243.}
244.
245.}
246.
247.public String chooseMessage() {
248.
249.int index = random.nextInt(keys.length);
250.String msg = keys[index];
251.
252.// 如果 10 次就选中 Bye,则重新选择,为了使对话内容多一些
253.if (messageCount < 10 && msg.equalsIgnoreCase("Bye")) {
254. return chooseMessage();
255.}
256.
257.return msg;
258.}
259.
260.// 接收线程
261.class RecieverThread extends Thread {
262.private InputStream ins;
263.
264.public RecieverThread(InputStream ins) {
265. this.ins = ins;
266.}
267.
268.@Override
269.public void run() {
270.
271. try {
272. String line = null;
273.
274. BufferedReader r = new BufferedReader(new InputStreamReader(
275. ins, "UTF-8"));
276.
277. // readLine()会阻塞,直到服务器输出一个 '\n'
278. while ((line = r.readLine()) != null) {
279.
280. System.out.println("[Recieved]: " + line);
281.
282. synchronized (ins) {
283. // 接收到服务器的消息,通知下主线程
284. ins.notify();
285. }
286. if (line.trim().equals("Bye")) {
287. exist = true;
288. break;
289. }
290. }
291. } catch (Exception e) {
292. e.printStackTrace();
293. }
294.}
295.
296.}
297.
298.public static void main(String[] args) throws Exception {
299.
300.// 开三个客户端线程
301.for (int i = 0; i < 3; i++) {
302. try {
303. new MyFirstNIOClientTest().start();
304. } catch (Exception e) {
305. e.printStackTrace();
306. }
307.}
308.
309.}
310.} //add by 郄永军