JavaSocket学习—NIO实现非阻塞的通信 以及几篇好文章 好好



Java网络编程——使用NIO实现非阻塞Socket通信

https://blog.csdn.net/yanmei_yao/article/details/8586199

JavaSocket学习—NIO实现非阻塞的通信

https://blog.csdn.net/henushang/article/details/84653615

Java Socket(六) 使用多线程实现多客户端的通信

https://blog.csdn.net/u013007900/article/details/50411649

Socket 多线程客户端与服务端(借鉴了他人)

https://blog.csdn.net/m0_38089615/article/details/80444794

java socket通信I/O阻塞>多线程实现非阻塞通信

https://blog.csdn.net/heroboyluck/article/details/78416782

 

 

示例代码见附件:很遗憾,太懒,代码内容还是我分的包,如果你要运行的话,还需要自己下一点小的功夫,改变一下包路径。

 

 

Server端代码:

  1. package com.henushang.socket.chapter4nio;
  2. import java.io.IOException;
  3. import java.net.InetSocketAddress;
  4. import java.nio.ByteBuffer;
  5. import java.nio.CharBuffer;
  6. import java.nio.channels.SelectionKey;
  7. import java.nio.channels.Selector;
  8. import java.nio.channels.ServerSocketChannel;
  9. import java.nio.channels.SocketChannel;
  10. import java.nio.charset.Charset;
  11. import java.util.Iterator;
  12. import java.util.Set;
  13. public class EchoServerNoBlock {
  14. private int port = 8000;
  15. private ServerSocketChannel serverSocketChannel;
  16. Selector selector;
  17. public EchoServerNoBlock() throws Exception {
  18. selector = Selector.open();
  19. serverSocketChannel = ServerSocketChannel.open();
  20. serverSocketChannel.socket().setReuseAddress(true);
  21. serverSocketChannel.configureBlocking(false);// 设置通信为非阻塞模式,没有这一配置,则无法实现非阻塞
  22. serverSocketChannel.socket().bind(new InetSocketAddress(port));
  23. System.out.println(“等待连接…”);
  24. }
  25. public void service() throws Exception {
  26. serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
  27. while (selector.select() > 0) {
  28. Set<SelectionKey> readyKeys = selector.selectedKeys();
  29. Iterator<SelectionKey> iterator = readyKeys.iterator();
  30. SelectionKey key = null;
  31. while (iterator.hasNext()) {
  32. try {
  33. key = iterator.next();
  34. iterator.remove();
  35. if (key.isAcceptable()) {
  36. System.out.println(“accept”);
  37. ServerSocketChannel ssc = (ServerSocketChannel) key
  38. .channel();
  39. SocketChannel sc = ssc.accept();
  40. System.out.println(“接收到链接”
  41. + sc.socket().getInetAddress() + “:”
  42. + sc.socket().getPort());
  43. sc.configureBlocking(false);
  44. ByteBuffer buffer = ByteBuffer.allocate(1024);
  45. sc.register(selector, SelectionKey.OP_READ
  46. | SelectionKey.OP_WRITE, buffer);
  47. }
  48. if (key.isReadable()) {
  49. System.out.println(“read”);
  50. receive(key);
  51. }
  52. if (key.isWritable()) {
  53. send(key);
  54. }
  55. } catch (Exception e) {
  56. e.printStackTrace();
  57. if (key != null) {
  58. key.cancel();
  59. key.channel().close();
  60. }
  61. }
  62. }
  63. }
  64. }
  65. /**
  66. * 发送消息处理方法
  67. * @param key
  68. * @throws Exception
  69. * @author henushang
  70. */
  71. public void send(SelectionKey key) throws Exception {
  72. ByteBuffer buffer = (ByteBuffer) key.attachment();
  73. SocketChannel socketChannel = (SocketChannel) key.channel();
  74. buffer.flip();
  75. String data = decode(buffer);
  76. if (data.indexOf(“\r\n”) == -1) {
  77. return;
  78. }
  79. String outputData = data.substring(0, data.indexOf(“\n”) + 1);
  80. System.out.println(outputData);
  81. ByteBuffer outputBuffer = encode(“henushang:” + outputData);
  82. while (outputBuffer.hasRemaining()) {
  83. socketChannel.write(outputBuffer);
  84. }
  85. ByteBuffer temp = encode(outputData);
  86. buffer.position(temp.limit());
  87. buffer.compact();
  88. if (outputData.equals(“byt\r\n”)) {
  89. key.cancel();
  90. socketChannel.close();
  91. System.out.println(“关闭连接”);
  92. }
  93. }
  94. /**
  95. * 接受链接处理方法
  96. * @param key
  97. * @throws IOException
  98. * @author henushang
  99. */
  100. public void receive(SelectionKey key) throws IOException {
  101. SocketChannel sc = (SocketChannel) key.channel();
  102. ByteBuffer buffer = (ByteBuffer) key.attachment();
  103. ByteBuffer readBuffer = ByteBuffer.allocate(32);
  104. sc.read(readBuffer);
  105. readBuffer.flip();
  106. buffer.limit(readBuffer.capacity());
  107. buffer.put(readBuffer);
  108. }
  109. static Charset charset = Charset.forName(“UTF-8″);
  110. /**
  111. * 解码
  112. * @param byteBuffer
  113. * @return
  114. * @author henushang
  115. */
  116. public static String decode(ByteBuffer byteBuffer) {
  117. CharBuffer charBuffer = charset.decode(byteBuffer);
  118. return charBuffer.toString();
  119. }
  120. /**
  121. * 编码
  122. * @param msg
  123. * @return
  124. * @author henushang
  125. */
  126. public static ByteBuffer encode(String msg) {
  127. return charset.encode(msg);
  128. }
  129. }

 


客户端代码:

  1. package com.henushang.socket.chapter4nio;
  2. import java.io.BufferedReader;
  3. import java.io.IOException;
  4. import java.io.InputStreamReader;
  5. import java.io.PrintWriter;
  6. import java.net.InetAddress;
  7. import java.net.InetSocketAddress;
  8. import java.nio.channels.SocketChannel;
  9. import com.henushang.socket.util.SocketUtils;
  10. public class EchoClient {
  11. private SocketChannel socketChannel;
  12. private int port = 8000;
  13. public EchoClient() throws Exception {
  14. socketChannel = SocketChannel.open();
  15. InetAddress inetAddress = InetAddress.getLocalHost();
  16. InetSocketAddress inetSocketAddress = new InetSocketAddress(inetAddress, port);
  17. socketChannel.connect(inetSocketAddress);
  18. System.out.println(“准备连接服务器”);
  19. }
  20. public static void main(String[] args) throws Exception {
  21. new EchoClient().talk();
  22. }
  23. public void talk() {
  24. try {
  25. BufferedReader reader = SocketUtils.getReader(socketChannel.socket());
  26. PrintWriter pw = SocketUtils.getWriter(socketChannel.socket());
  27. BufferedReader localreaderReader = new BufferedReader(new InputStreamReader(System.in));
  28. String msg = null;
  29. while ((msg = localreaderReader.readLine()) != null) {
  30. System.out.println(msg);
  31. pw.println(msg);
  32. pw.flush();
  33. System.out.println(reader.readLine());
  34. if (“bye”.equals(msg)) {
  35. break;
  36. }
  37. }
  38. } catch (IOException e) {
  39. e.printStackTrace();
  40. }finally{
  41. SocketUtils.close(socketChannel);
  42. }
  43. }
  44. }

 

工具类代码:

  1. package com.henushang.socket.util;
  2. import java.io.BufferedReader;
  3. import java.io.IOException;
  4. import java.io.InputStream;
  5. import java.io.InputStreamReader;
  6. import java.io.OutputStream;
  7. import java.io.PrintWriter;
  8. import java.net.Socket;
  9. import java.nio.channels.SocketChannel;
  10. public class SocketUtils {
  11. public static PrintWriter getWriter(Socket socket) throws IOException {
  12. OutputStream os = socket.getOutputStream();
  13. return new PrintWriter(os);
  14. }
  15. public static PrintWriter getWriter(SocketChannel socketChannel) throws IOException {
  16. return getWriter(socketChannel.socket());
  17. }
  18. public static BufferedReader getReader(Socket socket) throws IOException{
  19. InputStream is = socket.getInputStream();
  20. return new BufferedReader(new InputStreamReader(is, “UTF-8″));
  21. }
  22. public static BufferedReader getReader(SocketChannel socketChannel) throws IOException{
  23. return getReader(socketChannel.socket());
  24. }
  25. public static void close(Socket socket) {
  26. try {
  27. if (socket != null) {
  28. socket.close();
  29. }
  30. } catch (Exception e) {
  31. e.printStackTrace();
  32. }
  33. }
  34. public static void close(SocketChannel socketChannel) {
  35. try {
  36. if (socketChannel != null) {
  37. socketChannel.close();
  38. }
  39. } catch (Exception e) {
  40. e.printStackTrace();
  41. }
  42. }
  43. public static String echo(String msg) {
  44. return “echo:” + msg;
  45. }
  46. }

 

 

这种方式是一个线程在不停的循环检测监听到的事件,然后分别作出相应的处理。可是这种方式只适合那种处理过程时间短的情况,如果某一个操作处理的事件太长的话,则会让其他的事件一直处于等待状态,比如发送或者接收一个很大的文件,这样显然是很不合适的。

 

使用NIO的NoBlocking的操作方式固然减少了系统使用多线程建立连接的开销,但是也并不是完全适合任何情况的。

所以,在几种方式中没有最好的,只有最合适的。

 

而做程序也是一样的,没有那个语言是最好的,只有最合适的语言。