java NIO 服务器与多客户端双向通信 非阻塞

java NIO 服务器与多客户端双向通信 非阻塞

2017年05月25日 20:13:50 奔跑的阳光 阅读数:512

 版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_36961530/article/details/72743893

服务端代码:

 

 
  1. import java.io.BufferedReader;

  2. import java.io.IOException;

  3. import java.io.InputStreamReader;

  4. import java.net.InetSocketAddress;

  5. import java.nio.ByteBuffer;

  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.text.SimpleDateFormat;

  12. import java.util.Date;

  13. import java.util.HashMap;

  14. import java.util.Map;

  15. import java.util.Set;

  16.  
  17.  
  18. public class ServerSocket {

  19. private int port = 6001;

  20. //解码buffer

  21. // private CharsetDecoder decode = Charset.forName("UTF-8").newDecoder();

  22. /*发送数据缓冲区*/

  23. private ByteBuffer sBuffer = ByteBuffer.allocate(1024);

  24. /*接受数据缓冲区*/

  25. private ByteBuffer rBuffer = ByteBuffer.allocate(1024);

  26. /*映射客户端channel */

  27. private String sendText;

  28. private Map<String, SocketChannel> clientsMap = new HashMap<String, SocketChannel>();

  29. private Charset charset = Charset.forName("UTF-8");

  30. private Selector selector;

  31. private SimpleDateFormat sdf = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss", java.util.Locale.US);

  32. int i=0;

  33. public ServerSocket(){

  34. try {

  35. init();

  36. listen();

  37.  
  38. } catch (Exception e) {

  39. e.printStackTrace();

  40. }

  41. }

  42. private void init() throws Exception{

  43. /*

  44. *启动服务器端,配置为非阻塞,绑定端口,注册accept事件

  45. *ACCEPT事件:当服务端收到客户端连接请求时,触发该事件

  46. */

  47. ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

  48. serverSocketChannel.configureBlocking(false);

  49. java.net.ServerSocket serverSocket = serverSocketChannel.socket();

  50. serverSocket.bind(new InetSocketAddress(port));

  51. selector = Selector.open();

  52. serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

  53. System.out.println("server start on port:"+port);

  54. }

  55.  
  56. /**

  57. * 服务器端轮询监听,select方法会一直阻塞直到有相关事件发生或超时

  58. */

  59. private void listen(){

  60.  
  61. while (true) {

  62. try {

  63. selector.select();//返回值为本次触发的事件数

  64. Set<SelectionKey> selectionKeys = selector.selectedKeys();

  65. for(SelectionKey key : selectionKeys){

  66. handle(key);

  67. }

  68. selectionKeys.clear();//清除处理过的事件

  69. } catch (Exception e) {

  70. e.printStackTrace();

  71. break;

  72. }

  73. }

  74. }

  75.  
  76. /**

  77. * 处理不同的事件

  78. */

  79. private void handle(SelectionKey selectionKey) throws IOException {

  80.  
  81. ServerSocketChannel server = null;

  82. SocketChannel client = null;

  83. String receiveText=null;

  84. int count=0;

  85. if (selectionKey.isAcceptable()) {

  86. /*

  87. * 客户端请求连接事件

  88. * serversocket为该客户端建立socket连接,将此socket注册READ事件,监听客户端输入

  89. * READ事件:当客户端发来数据,并已被服务器控制线程正确读取时,触发该事件

  90. */

  91. server = (ServerSocketChannel) selectionKey.channel();

  92. client = server.accept();

  93. client.configureBlocking(false);

  94. clientsMap.put(client.getLocalAddress().toString().substring(1)+ i++,client);

  95. client.register(selector, SelectionKey.OP_READ);

  96. } else if (selectionKey.isReadable()) {

  97. /*

  98. * READ事件,收到客户端发送数据,读取数据后继续注册监听客户端

  99. */

  100. client = (SocketChannel) selectionKey.channel();

  101. rBuffer.clear();

  102. count = client.read(rBuffer);

  103. if (count > 0) {

  104. rBuffer.flip();

  105. receiveText = charset.decode(rBuffer.asReadOnlyBuffer()).toString();

  106. System.out.println(client.getLocalAddress().toString().substring(1)+":"+receiveText);

  107. sBuffer.clear();

  108. sBuffer.put((sdf.format(new Date())+"服务器收到你的消息").getBytes("UTF-8"));

  109. sBuffer.flip();

  110. client.write(sBuffer);

  111. new Thread(){

  112. @Override

  113. public void run() {

  114. while(true){

  115. try {

  116. //String name = "["+client.getInetAddress().toString().substring(1)+"]";

  117. InputStreamReader input = new InputStreamReader(System.in);

  118. BufferedReader br = new BufferedReader(input);

  119. sendText = br.readLine();

  120.  
  121. if(!clientsMap.isEmpty()){

  122. for(Map.Entry<String, SocketChannel> entry : clientsMap.entrySet()){

  123. SocketChannel temp = entry.getValue();

  124. String name=entry.getKey();

  125.  
  126. sBuffer.clear();

  127. sBuffer.put((name+":"+sendText).getBytes("UTF-8"));

  128. sBuffer.flip();

  129. //输出到通道

  130. temp.write(sBuffer);

  131. }

  132. }

  133. } catch (IOException e) {

  134. e.printStackTrace();

  135. break;

  136. }

  137. }

  138. }

  139. }.start();

  140.  
  141. client = (SocketChannel) selectionKey.channel();

  142. client.register(selector, SelectionKey.OP_READ);

  143. }

  144. }

  145.  
  146.  
  147. }

  148. public static void main(String[] args) throws IOException {

  149. new ServerSocket();

  150. }

  151. }


客户端代码:

 

 
  1. import com.sun.org.apache.xerces.internal.impl.xpath.regex.ParseException;

  2.  
  3. import java.io.BufferedReader;

  4. import java.io.IOException;

  5. import java.io.InputStreamReader;

  6. import java.net.InetSocketAddress;

  7. import java.nio.ByteBuffer;

  8. import java.nio.channels.SelectionKey;

  9. import java.nio.channels.Selector;

  10. import java.nio.channels.SocketChannel;

  11. import java.nio.charset.Charset;

  12. import java.text.SimpleDateFormat;

  13. import java.util.Date;

  14. import java.util.Set;

  15.  
  16.  
  17. public class Client {

  18. /*发送数据缓冲区*/

  19. private static ByteBuffer sBuffer = ByteBuffer.allocate(1024);

  20. /*接受数据缓冲区*/

  21. private static ByteBuffer rBuffer = ByteBuffer.allocate(1024);

  22. /*服务器端地址*/

  23. private InetSocketAddress SERVER;

  24. private Selector selector;

  25. private SocketChannel client;

  26. private String receiveText;

  27. private String sendText;

  28. private int count=0;

  29. private Charset charset = Charset.forName("UTF-8");

  30. private SimpleDateFormat sdf = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss", java.util.Locale.US);

  31.  
  32. public Client(){

  33.  
  34. SERVER = new InetSocketAddress("localhost", 6001);

  35. init();

  36. }

  37. /**

  38. *

  39. */

  40. public void init(){

  41.  
  42. try {

  43. /*

  44. * 客户端向服务器端发起建立连接请求

  45. */

  46. SocketChannel socketChannel = SocketChannel.open();

  47. socketChannel.configureBlocking(false);

  48. selector = Selector.open();

  49. socketChannel.register(selector, SelectionKey.OP_CONNECT);

  50. socketChannel.connect(SERVER);

  51. /*

  52. * 轮询监听客户端上注册事件的发生

  53. */

  54. while (true) {

  55. selector.select();

  56. Set<SelectionKey> keySet = selector.selectedKeys();

  57. for(final SelectionKey key : keySet){

  58. handle(key);

  59. }

  60. keySet.clear();

  61. }

  62. } catch (Exception e) {

  63. e.printStackTrace();

  64. }

  65. }

  66.  
  67. public static void main(String[] args) throws IOException {

  68.  
  69. new Client();

  70. }

  71.  
  72. /**

  73. * @param selectionKey

  74. * @throws IOException

  75. * @throws ParseException

  76. */

  77. private void handle(SelectionKey selectionKey) throws IOException, ParseException{

  78.  
  79. if (selectionKey.isConnectable()) {

  80. /*

  81. * 连接建立事件,已成功连接至服务器

  82. */

  83. client = (SocketChannel) selectionKey.channel();

  84. if (client.isConnectionPending()) {

  85. client.finishConnect();

  86. System.out.println("connect success !");

  87. sBuffer.clear();

  88. sBuffer.put((sdf.format(new Date())+" connected!你好").getBytes("UTF-8"));

  89. sBuffer.flip();

  90. client.write(sBuffer);//发送信息至服务器

  91. /*

  92. * 启动线程一直监听客户端输入,有信心输入则发往服务器端

  93. * 因为输入流是阻塞的,所以单独线程监听

  94. */

  95. new Thread(){

  96. @Override

  97. public void run() {

  98. while(true){

  99. try {

  100. sBuffer.clear();

  101. InputStreamReader input = new InputStreamReader(System.in);

  102. BufferedReader br = new BufferedReader(input);

  103. sendText = br.readLine();

  104.  
  105. sBuffer.put(sendText.trim().getBytes("UTF-8"));

  106. sBuffer.flip();

  107. client.write(sBuffer);

  108. } catch (IOException e) {

  109. e.printStackTrace();

  110. break;

  111. }

  112. }

  113. }

  114. }.start();

  115. }

  116. //注册读事件

  117. client.register(selector, SelectionKey.OP_READ);

  118. } else if (selectionKey.isReadable()) {

  119. /*

  120. * 读事件触发

  121. * 有从服务器端发送过来的信息,读取输出到屏幕上后,继续注册读事件

  122. * 监听服务器端发送信息

  123. */

  124. client = (SocketChannel) selectionKey.channel();

  125. count=client.read(rBuffer);

  126. if(count>0){

  127. receiveText = new String( rBuffer.array(),0,count);

  128. System.out.println(receiveText);

  129. client = (SocketChannel) selectionKey.channel();

  130. client.register(selector, SelectionKey.OP_READ);

  131. rBuffer.clear();

  132. }

  133. }

  134. }

  135.  
  136. }

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值