JAVA NIO工作原理及代码实例分析(7)

package nioDemo;
 
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Random;
import java.util.Set;
 
/*客户端:客户端每隔1~2秒自动向服务器发送数据,接收服务器接收到数据并显示*/
public class ClientSocketChannelDemo {
   
    public static class TCPEchoClient implements Runnable{
       
        /*客户端线程名*/
        private String name;
        private Random rnd = new Random();
       
        /*服务器的ip地址+端口port*/
        private InetSocketAddress remoteAddress;
       
        public TCPEchoClient(String name, InetSocketAddress remoteAddress){
            this.name = name;
            this.remoteAddress = remoteAddress;
        }
       
        @Override
        public void run(){
           
            /*创建解码器*/
            Charset utf8 = Charset.forName("UTF-8");
           
            Selector selector;
           
            try {
               
                /*创建TCP通道*/
                SocketChannel sc = SocketChannel.open();
               
                /*设置通道为非阻塞*/
                sc.configureBlocking(false);
               
                /*创建选择器*/
                selector = Selector.open();
               
                /*注册感兴趣事件*/
                int interestSet = SelectionKey.OP_READ | SelectionKey.OP_WRITE;
               
                /*向选择器注册通道*/
                sc.register(selector, interestSet, new Buffers(256, 256));
               
                /*向服务器发起连接,一个通道代表一条tcp链接*/
                sc.connect(remoteAddress);
               
                /*等待三次握手完成*/
                while(!sc.finishConnect()){
                    ;
                }
 
                System.out.println(name + " " + "finished connection");
               
            } catch (IOException e) {
                System.out.println("client connect failed");
                return;
            }
           
            /*与服务器断开或线程被中断则结束线程*/
            try{
 
                int i = 1;
                while(!Thread.currentThread().isInterrupted()){
                   
                    /*阻塞等待*/
                    selector.select();
                   
                    /*Set中的每个key代表一个通道*/
                    Set<SelectionKey> keySet = selector.selectedKeys();
                    Iterator<SelectionKey> it = keySet.iterator();
                   
                    /*遍历每个已就绪的通道,处理这个通道已就绪的事件*/
                    while(it.hasNext()){
                       
                        SelectionKey key = it.next();
                        /*防止下次select方法返回已处理过的通道*/
                        it.remove();
                       
                        /*通过SelectionKey获取对应的通道*/
                        Buffers  buffers = (Buffers)key.attachment();
                        ByteBuffer readBuffer = buffers.getReadBuffer();
                        ByteBuffer writeBuffer = buffers.gerWriteBuffer();
                       
                        /*通过SelectionKey获取通道对应的缓冲区*/
                        SocketChannel sc = (SocketChannel) key.channel();
                       
                        /*表示底层socket的读缓冲区有数据可读*/
                        if(key.isReadable()){
                            /*从socket的读缓冲区读取到程序定义的缓冲区中*/
                            sc.read(readBuffer);
                            readBuffer.flip();
                            /*字节到utf8解码*/
                            CharBuffer cb = utf8.decode(readBuffer);
                            /*显示接收到由服务器发送的信息*/
                            System.out.println(cb.array());
                            readBuffer.clear();
                        }
                       
                        /*socket的写缓冲区可写*/
                        if(key.isWritable()){
                            writeBuffer.put((name + "  " + i).getBytes("UTF-8"));
                            writeBuffer.flip();
                            /*将程序定义的缓冲区中的内容写入到socket的写缓冲区中*/
                            sc.write(writeBuffer);
                            writeBuffer.clear();
                            i++;
                        }
                    }
                   
                    Thread.sleep(1000 + rnd.nextInt(1000));
                }
           
            }catch(InterruptedException e){
                System.out.println(name + " is interrupted");
            }catch(IOException e){
                System.out.println(name + " encounter a connect error");
            }finally{
                try {
                    selector.close();
                } catch (IOException e1) {
                    System.out.println(name + " close selector failed");
                }finally{
                    System.out.println(name + "  closed");
                }
            }
        }
       
    }
   
    public static void main(String[] args) throws InterruptedException{
       
        InetSocketAddress remoteAddress = new InetSocketAddress("192.168.1.100", 8080);
       
        Thread ta = new Thread(new TCPEchoClient("thread a", remoteAddress));
        Thread tb = new Thread(new TCPEchoClient("thread b", remoteAddress));
        Thread tc = new Thread(new TCPEchoClient("thread c", remoteAddress));
        Thread td = new Thread(new TCPEchoClient("thread d", remoteAddress));
       
        ta.start();
        tb.start();
        tc.start();
       
        Thread.sleep(5000);
 
        /*结束客户端a*/
        ta.interrupt();
       
        /*开始客户端d*/
        td.start();
    }
}

5.2 UDP示例

客户端非阻塞模式,服务器端阻塞模式

1)服务器端代码(服务器端只有一个通道,对应一个读缓冲区,一个写缓冲区,所以使用非阻塞方式容易发生数据混乱)

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/39980f0e5d16638c925b21f6b950f590.html