Java NIO实现聊天功能

 更新时间:2021年11月24日 12:13:09   作者:TCH987551623  
这篇文章主要为大家详细介绍了Java NIO实现聊天功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

本文实例为大家分享了Java NIO实现聊天功能的具体代码,供大家参考,具体内容如下

server code : 

package com.tch.test.nio;
 
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
 
public class NioServer {
 
 private SocketChannel socketChannel = null;
 private Set<SelectionKey> selectionKeys = null;
 private Iterator<SelectionKey> iterator = null;
 private Iterator<SocketChannel> iterator2 = null;
 private SelectionKey selectionKey = null;
 
 public static void main(String[] args) {
  new NioServer().start();
 }
 
 private void start(){
  try {
   //create serverSocketChannel
   ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
   //bind the serverSocketChannel to a port
   serverSocketChannel.bind(new InetSocketAddress(7878));
   //when using selector ,should config the blocking mode of serverSocketChannel to non-blocking
   serverSocketChannel.configureBlocking(false);
   //create a selector to manage all the channels
   Selector selector = Selector.open();
   //reigst the serverSocketChannel to the selector(interest in accept event)
   serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
   //create a list to store all the SocketChannels
   List<SocketChannel> clients = new ArrayList<SocketChannel>();
   //create a ByteBuffer to store data
   ByteBuffer buffer = ByteBuffer.allocate(1024);
   while(true){
    //this method will block until at least one of the interested events is ready 
    int ready = selector.select();
    if(ready > 0){//means at least one of the interested events is ready 
     selectionKeys = selector.selectedKeys();
     iterator = selectionKeys.iterator();
     while(iterator.hasNext()){
                        //the selectionKey contains the channel and the event which the channel is interested in 
                        selectionKey = iterator.next();
                        //accept event , means new client reaches
                        if(selectionKey.isAcceptable()){
                            //handle new client
                            ServerSocketChannel serverSocketChannel2 = (ServerSocketChannel)selectionKey.channel();
                            socketChannel = serverSocketChannel2.accept();
                            //when using selector , should config the blocking mode of socketChannel to non-blocking
                            socketChannel.configureBlocking(false);
                            //regist the socketChannel to the selector
                            socketChannel.register(selector, SelectionKey.OP_READ);
                            //add to client list
                            clients.add(socketChannel);
                        }else if(selectionKey.isReadable()){
                            //read message from client
                            socketChannel = (SocketChannel)selectionKey.channel();
                            buffer.clear();
                            try {
                                socketChannel.read(buffer);
                                buffer.flip();
                                //send message to every client
                                iterator2 = clients.iterator();
                                SocketChannel socketChannel2 = null;
                                while(iterator2.hasNext()){
                                    socketChannel2 = iterator2.next();
                                    while(buffer.hasRemaining()){
                                        socketChannel2.write(buffer);
                                    }
                                    //rewind method makes the buffer ready to the next read operation
                                    buffer.rewind();
                                }
                            } catch (IOException e) {
                                // IOException occured on the channel, remove from channel list
                                e.printStackTrace();
                                // Note: close the channel
                                socketChannel.close();
                                iterator2 = clients.iterator();
                                while(iterator2.hasNext()){
                                    if(socketChannel == iterator2.next()){
                                        // remove the channel
                                        iterator2.remove();
                                        System.out.println("remove the closed channel from client list ...");
                                        break;
                                    }
                                }
                            }
                        }
                        //important , remember to remove the channel after all the operations. so that the next selector.select() will 
                        //return this channel again .
      iterator.remove();
     }
    }
   }
  } catch (ClosedChannelException e) {
   e.printStackTrace();
  } catch (IOException e) {
   e.printStackTrace();
  }
 }
 
}

client code : 

package com.tch.nio.test;
 
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
 
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.JTextField;
 
public class NioClient extends JFrame{
 
 private static final long serialVersionUID = 1L;
 private JTextArea area = new JTextArea("content :");
 private JTextField textField = new JTextField("textfield:");
 private JButton button = new JButton("send");
 private SocketChannel socketChannel = null;
 private ByteBuffer buffer = ByteBuffer.allocate(1024);
 private ByteBuffer buffer2 = ByteBuffer.allocate(1024);
 private String message = null;
 
 public static void main(String[] args) throws Exception {
  NioClient client = new NioClient();
  client.start();
 }
 
 private void start() throws IOException{
  setBounds(200, 200, 300, 400);
  setLayout(new GridLayout(3, 1));
  add(area);
  add(textField);
  //create a socketChannel and connect to the specified address
  socketChannel = SocketChannel.open(new InetSocketAddress("localhost", 7878));
  //when using selector , should config the blocking mode of socketChannel to non-blocking
  socketChannel.configureBlocking(false);
  button.addActionListener(new ActionListener() {
   @Override
   public void actionPerformed(ActionEvent event) {
    try {
     message = textField.getText();
     textField.setText("");
     //send message to server
     buffer.put(message.getBytes("utf-8"));
     buffer.flip();
     while(buffer.hasRemaining()){
      socketChannel.write(buffer);
     }
     buffer.clear();
    } catch (Exception e) {
     e.printStackTrace();
    }
   }
  });
  add(button);
  setDefaultCloseOperation(EXIT_ON_CLOSE);
  setVisible(true);
  Set<SelectionKey> selectionKeys = null;
  Iterator<SelectionKey> iterator = null;
  SelectionKey selectionKey = null;
  Selector selector = Selector.open();
  //reigst the socketChannel to the selector(interest in read event)
  socketChannel.register(selector, SelectionKey.OP_READ);
  while(true){
   //this method will block until at least one of the interested events is ready 
   int ready = selector.select();
   if(ready > 0){//means at least one of the interested events is ready 
    selectionKeys = selector.selectedKeys();
    iterator = selectionKeys.iterator();
    while(iterator.hasNext()){
     selectionKey = iterator.next();
     //read message from server ,then append the message to textarea
     if(selectionKey.isReadable()){
      socketChannel.read(buffer2);
      buffer2.flip();
      area.setText(area.getText().trim()+"\n"+new String(buffer2.array(),0,buffer2.limit(),"utf-8"));
      buffer2.clear();
     }
     //important , remember to remove the channel after all the operations. so that the next selector.select() will 
     //return this channel again .
     iterator.remove();
    }
   }
  }
 }
 
}

run server first , then is client , type message and send , ok

使用Mina实现聊天:

server:

package com.tch.test.jms.origin.server;
 
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
 
import org.apache.mina.core.service.IoAcceptor;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
public class MyServer {
 
 private static final Logger LOGGER = LoggerFactory.getLogger(MyServer.class);
 private List<IoSession> clientSessionList = new ArrayList<IoSession>();
 
 public static void main(String[] args) {
     
  IoAcceptor acceptor = new NioSocketAcceptor();
 
  acceptor.getFilterChain().addLast("logger", new LoggingFilter());
  acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"))));
 
  acceptor.setHandler(new MyServer().new MyServerIoHandler());
  
  try {
   acceptor.bind(new InetSocketAddress(10000));
  } catch (IOException ex) {
   LOGGER.error(ex.getMessage(), ex);
  }
 }
 
 class MyServerIoHandler extends IoHandlerAdapter{
        
        @Override
        public void sessionCreated(IoSession session) throws Exception {
            LOGGER.info("sessionCreated");
        }
        
        @Override
        public void sessionOpened(IoSession session) throws Exception {
            LOGGER.info("sessionOpened");
            if(! clientSessionList.contains(session)){
                clientSessionList.add(session);
            }
        }
 
        @Override
        public void sessionClosed(IoSession session) throws Exception {
            LOGGER.info("sessionClosed");
            clientSessionList.remove(session);
        }
 
        @Override
        public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
            LOGGER.info("sessionIdle");
        }
 
        @Override
        public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
            LOGGER.error(cause.getMessage(), cause);
            session.close(true);
            clientSessionList.remove(session);
        }
 
        @Override
        public void messageReceived(IoSession session, Object message) throws Exception {
            LOGGER.info("messageReceived:" + message);
            for(IoSession clientSession : clientSessionList){
                clientSession.write(message);
            }
        }
 
        @Override
        public void messageSent(IoSession session, Object message) throws Exception {
            LOGGER.info("messageSent:" + message);
        }
    }
}

client :

package com.tch.test.jms.origin.client;
 
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
 
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.JTextField;
 
import org.apache.mina.core.RuntimeIoException;
import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.core.service.IoConnector;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.socket.nio.NioSocketConnector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
public class NioClient extends JFrame{
    private static final Logger LOGGER = LoggerFactory.getLogger(NioClient.class);
 private static final long serialVersionUID = 1L;
 private JTextArea area = new JTextArea("content :");
 private JTextField textField = new JTextField("textfield:");
 private JButton button = new JButton("send");
 private String message = null;
 private MyClientIoHandler handler;
 private IoSession session;
 
 public static void main(String[] args) throws Exception {
  NioClient client = new NioClient();
  client.start();
 }
 
 private void start() throws IOException{
  setBounds(200, 200, 300, 400);
  setLayout(new GridLayout(3, 1));
  add(area);
  add(textField);
  
  IoConnector connector = new NioSocketConnector();
        connector.setConnectTimeoutMillis(10 * 1000);
        
        connector.getFilterChain().addLast("logger", new LoggingFilter());
        connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"))));
        
        handler = new MyClientIoHandler(this);
        connector.setHandler(handler);
  
  button.addActionListener(new ActionListener() {
   @Override
   public void actionPerformed(ActionEvent event) {
       sendMessage();
   }
  });
  add(button);
  setDefaultCloseOperation(EXIT_ON_CLOSE);
  setVisible(true);
  
  IoSession session = null;
        try {
            ConnectFuture future = connector.connect(new InetSocketAddress("localhost", 10000));
            future.awaitUninterruptibly();
            session = future.getSession();
        } catch (RuntimeIoException e) {
            LOGGER.error(e.getMessage(), e);
        }
        session.getCloseFuture().awaitUninterruptibly();
        connector.dispose();
 }
 
 private void sendMessage() {
        try {
            message = textField.getText();
            textField.setText("");
            if(session == null || ! session.isConnected()){
                throw new RuntimeException("session is null");
            }
            session.write(message);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
 
 class MyClientIoHandler extends IoHandlerAdapter{
     private NioClient client;
        public MyClientIoHandler(NioClient client){
            this.client = client;
        }
        @Override
        public void sessionCreated(IoSession session) throws Exception {
            LOGGER.info("sessionCreated");
        }
 
        @Override
        public void sessionOpened(IoSession session) throws Exception {
            LOGGER.info("sessionOpened");
            client.session = session;
        }
 
        @Override
        public void sessionClosed(IoSession session) throws Exception {
            LOGGER.info("sessionClosed");
        }
 
        @Override
        public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
            LOGGER.info("sessionIdle");
        }
 
        @Override
        public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
            LOGGER.error(cause.getMessage(), cause);
            session.close(true);
        }
 
        @Override
        public void messageReceived(IoSession session, Object message) throws Exception {
            LOGGER.info("messageReceived: " + message);
            if (message.toString().equalsIgnoreCase("Bye")) {
                session.close(true);
            }
            area.setText(area.getText().trim()+"\n"+message);
        }
 
        @Override
        public void messageSent(IoSession session, Object message) throws Exception {
            LOGGER.info("messageSent: " + message);
        }
    }
 
}

OK.

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • 详解MyBatis-Plus updateById方法更新不了空字符串/null解决方法

    详解MyBatis-Plus updateById方法更新不了空字符串/null解决方法

    这篇文章主要介绍了详解MyBatis-Plus updateById方法更新不了空字符串/null解决方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-09-09
  • 深入学习springboot线程池的使用和扩展

    深入学习springboot线程池的使用和扩展

    这篇文章主要介绍了深入学习springboot线程池的使用和扩展,springboot框架提供了@Async注解,帮助我们更方便的将业务逻辑提交到线程池中异步执行,需要的朋友可以参考下
    2019-06-06
  • Mapper类中存在名称相同的方法重载报错问题

    Mapper类中存在名称相同的方法重载报错问题

    这篇文章主要介绍了Mapper类中存在名称相同的方法重载报错问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-03-03
  • Spring事务失效之常见场景分析

    Spring事务失效之常见场景分析

    这篇文章主要介绍了Spring事务失效之常见场景,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-04-04
  • 简单讲解奇偶排序算法及在Java数组中的实现

    简单讲解奇偶排序算法及在Java数组中的实现

    这篇文章主要介绍了奇偶排序算法及Java数组的实现,奇偶排序的时间复杂度为O(N^2),需要的朋友可以参考下
    2016-04-04
  • SpringMVC视图转发重定向区别及控制器详解

    SpringMVC视图转发重定向区别及控制器详解

    这篇文章主要为大家介绍了SpringMVC视图转发重定向区别及控制器示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-05-05
  • 详解MyBatis的XML实现方法(附带注解方式实现)

    详解MyBatis的XML实现方法(附带注解方式实现)

    这篇文章主要详细介绍了MyBatis的XML实现方法(附带注解方式实现),文中通过代码示例给大家讲解的非常详细,对大家的学习或工作有一定的帮助,需要的朋友可以参考下
    2024-05-05
  • Java System类两个常用方法代码实例

    Java System类两个常用方法代码实例

    这篇文章主要介绍了Java System类两个常用方法代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-02-02
  • springboot全局异常处理详解

    springboot全局异常处理详解

    本篇文章主要介绍了springboot全局异常处理详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-05-05
  • 本真的REST架构风格理解

    本真的REST架构风格理解

    这篇文章主要为大家介绍了本真的REST架构风格的深入理解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-03-03

最新评论