NIO实现TCP聊天室

2. Selector选择器老大

2.4.1 Selector

选择器,网络编程使用NIO的大哥!!!
服务器可以执行一个线程,运行Selector程序,进行监听操作。
新连接, 已经连接, 读取数据,写入数据

Selector常用方法:
public static Selector Open();
得到一个选择器对象
public int select(long timeout);
监听所有注册通道,存在IO流操作是,会将对应的 信息SelectionKey存入到内部的集合中,参数是 一个超时时间
public Set selectionKeys();
返回当前Selector内部集合中保存的所有 SelectionKey

2.4.2 SelectionKey

SelectionKey
表示Selector和网络通道直接的关系
int OP_ACCEPT; 16 需要连接
int OP_CONNECT; 8 已经连接
int OP_READ; 1 读取操作
int OP_WRITE; 4 写入操作
SelectionKey
public abstract Selector selector(); 得到与之关联的 Selector 对象
public abstract SelectableChannel channel(); 得到与之关联的通道
public final Object attachment(); 得到与之关联的共享数据
public abstract SelectionKey interestOps(int ops); 设置或改变监听事件
public final boolean isAcceptable(); 是否可以 accept
public final boolean isReadable(); 是否可以读
public final boolean isWritable(); 是否可以写

2.4.3 ServerSocketChannel

ServerSocketChannel 服务端Socket程序对应的Channel通道
常用方法:
public static ServerSocketChannel open();
开启服务器ServerSocketChannel通道,等于开始 服务器程序
public final ServerSocketChannel bind(SocketAddress local);
设置服务器端端口号
public final SelectableChannel configureBlocking(boolean block);
设置阻塞或非阻塞模式, 取值 false 表示采用非 阻塞模式
public SocketChannel accept();
[非阻塞] 获取一个客户端连接,并且得到对应的操作通 道
public final SelectionKey register(Selector sel, int ops);
[重点方法] 注册当前选择器,并且选择监听什么事件

2.4.4 SocketChannel

SocketChannel 客户端Socket对应的Channel对象
常用方法:
public static SocketChannel open();
打卡一个Socket客户端Channel对象
public final SelectableChannel configureBlocking(boolean block)
这里可以设置是阻塞状态,还是非阻塞状态
false,表示非阻塞
public boolean connect(SocketAddress remote);
连接服务器
public boolean finishConnect();
如果connect连接失败,可以通过finishConnect 继续连接
public int write(ByteBuffer buf);
写入数据到缓冲流中
public int read(ByteBuffer buf);
从缓冲流中读取数据
public final SelectionKey register(Selector sel, int ops, Object attechment);
注册当前SocketChannel,选择对应的监听操作, 并且可以带有Object attachment参数
public final void close(); 关闭SocketChannel

package com.my.demo2;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;

public class ChatClient {
    private String userName ;
    private static final String HOST = "192.168.0.107";
    private static final int PORT = 8080 ;
    private SocketChannel channel ;

    public ChatClient(String userName) throws IOException, InterruptedException {
        channel = SocketChannel.open();
        channel.configureBlocking(false);
        InetSocketAddress address = new InetSocketAddress(HOST , PORT) ;
        if (!channel.connect(address)) {
            while (!channel.finishConnect()) {
                System.out.println("服务器连接失败,两秒后自动重连,请稍后...");
                Thread.sleep(2000);
            }
        }
        this.userName = userName ;
        System.out.println("客户端:" + userName + "准备就绪!");
    }
    public void send(String message) throws IOException {
        if ("close".equals(message)) {
            System.out.println("聊天结束...");
            channel.close();
            return;
        }
        message = userName + ":" + message ;
        ByteBuffer buffer= ByteBuffer.wrap(message.getBytes()) ;
        channel.write(buffer) ;
    }
    public void receive() throws IOException {
        ByteBuffer buffer = ByteBuffer.allocate(1024) ;
        int length = channel.read(buffer);
        if (length > 0) {
            System.out.println(new String(buffer.array()));
        }
    }
}

package com.my.demo2;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;

public class ChatServer {
    private ServerSocketChannel serverSocket;
    private Selector selector;
    private static final int PORT = 8848;

    public ChatServer() throws IOException {
        serverSocket = ServerSocketChannel.open();
        selector = Selector.open();
        serverSocket.bind(new InetSocketAddress(PORT));
        serverSocket.register(selector, SelectionKey.OP_ACCEPT);
    }

    public void start() {
        while (true) {
            try {
                if (0 == selector.select()) {
                    System.out.println("暂时无人连接服务器...");
                    continue;
                }
                Iterator<SelectionKey> iterators = selector.selectedKeys().iterator();
                while (iterators.hasNext()) {
                    SelectionKey selectionKey = iterators.next();
                    if (selectionKey.isAcceptable()) {
                        SocketChannel channel = serverSocket.accept();
                        channel.configureBlocking(false);
                        channel.register(selector, SelectionKey.OP_ACCEPT);
                        broadcast(channel, channel.getRemoteAddress().toString() + "上线了");

                    }
                    if (selectionKey.isReadable()) {
                        readMsg(selectionKey);
                    }
                    iterators.remove();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

        }

    }

    private void readMsg(SelectionKey key) throws IOException {
        SocketChannel socket = (SocketChannel) key.channel();
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        int length = socket.read(buffer);
        if (length > 0) {
            String message = new String(buffer.array());
            broadcast(socket, message);
        }
    }


    private void broadcast(SocketChannel self, String message) throws IOException {
        Set<SelectionKey> keys = selector.keys();
        for (SelectionKey key : keys) {
            SelectableChannel channel = key.channel();
            if (channel instanceof SocketChannel && !channel.equals(self)) {
                SocketChannel socketChannel = (SocketChannel) channel;
                ByteBuffer buffer = ByteBuffer.wrap(message.getBytes());
                socketChannel.write(buffer);
            }
        }
    }

    public static void main(String[] args) throws IOException {
        new ChatServer().start();
    }
}

package com.my.demo2;

import java.io.IOException;
import java.util.Scanner;

public class ChatClientThreads {
    public static void main(String[] args) throws IOException, InterruptedException {
        Scanner scanner = new Scanner(System.in);

        System.out.println("请输入用户名:");
        String userName = scanner.nextLine();

        if (0 == userName.length()) {
            return;
        }

        ChatClient chatClient = new ChatClient(userName);
        new Thread(() -> {
            while (true) {
                try {
                    chatClient.receive();
                    Thread.sleep(2000);
                } catch (IOException | InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        while (scanner.hasNextLine()) {
            String msg = scanner.nextLine();

            chatClient.send(msg);
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值