基于nio/多线程/socket的群聊系统

最近在学netty 复习了一下java高级的io,多线程,网络编程
今天分享一下我练得小综合项目

NI/O是I/O的加强版 ,IO就是人机或机机交互的接口
三大特性:channel(通道),buffer(缓存),selector(选择器)

上代码
Server

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

public class ChatServer {

    private ServerSocketChannel channel;

    private Selector selector;

    public ChatServer() {
        try {
            channel = ServerSocketChannel.open();

            selector = Selector.open();

            SocketAddress address = new InetSocketAddress(6666);

            channel.socket().bind(address);

            channel.configureBlocking(false);
            //注册通道的可接收事件
            channel.register(selector, SelectionKey.OP_ACCEPT);
        } catch (IOException e) {
            e.printStackTrace();
        }


    }

    //监听客户端
    public void listenClient() throws Exception {
        System.out.println("服务器启动监听");
        //轮询选择器
        while (true) {
            int num = selector.select();

            if (num == 0) continue;

            //接收连接
            Set<SelectionKey> set = selector.selectedKeys();
            Iterator<SelectionKey> it = set.iterator();

            //处理连接
            while (it.hasNext()) {

                SelectionKey key = it.next();
                it.remove();
                /*
                 *  识别key对应的事件
                 */
                if (key.isAcceptable()) {
                    SocketChannel clientChannel = channel.accept();
                    //设置线程非阻塞
                    clientChannel.configureBlocking(false);
                    //注册监听下次的读事件
                    clientChannel.register(selector, SelectionKey.OP_READ);
                    //提示
                    System.out.println("user   " + clientChannel.socket().getRemoteSocketAddress() + "  登录");
                    continue;

                }
                if (key.isReadable()) {
                    //接收客户端消息
                    readData(key);
                }

            }

        }
    }

    /*
     * 接收msg
     */
    private void readData(SelectionKey key) throws Exception {

        SocketChannel channel = null;
        try {
            //接收channel抽象类  要强转
            channel = (SocketChannel) key.channel();
            //给缓冲区 分配内存
            ByteBuffer buffer = ByteBuffer.allocate(1024);

            int num = channel.read(buffer);
            if (num > 0) {
                String msg = new String(buffer.array());
                msg=msg+"  from>>   "+channel.socket().getRemoteSocketAddress();
                System.out.println("msg : " + msg);
                //广播消息
                sendToOther(msg, channel);
            }

        } catch (Exception e) {
            //channel置空则用户下线

            System.out.println("user : "+ channel.socket().getRemoteSocketAddress()+"下线");
            //注销selector
            key.cancel();
            //关闭通道
            try {
                channel.close();
            }catch (Exception e1){
                e1.printStackTrace();
            }
        }
    }

    /*
     *  广播消息给其他用户
     */
    private void sendToOther(String msg, SocketChannel selfChannel)throws Exception {
        Set<SelectionKey> set = selector.keys();
        for (SelectionKey key : set) {

            Channel channel = key.channel();
            //判断管道是否属于除发消息外其他用户
            if (channel instanceof SocketChannel && channel != selfChannel) {
                SocketChannel socketChannel = (SocketChannel) channel;
                //直接把数据分到缓冲区
                ByteBuffer buffer = ByteBuffer.wrap(msg.getBytes());
                //写入
                socketChannel.write(buffer);
            }
        }
    }

    public static void main(String[] args) throws Exception {
        //初始化服务器
        ChatServer server=new ChatServer();
        server.listenClient();
    }
}

客户端

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
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.Scanner;
import java.util.Set;

public class ChatClient {

    private SocketChannel channel;

    private Selector selector;

    //构造器
    public ChatClient() {
        try {
            selector = Selector.open();
            SocketAddress address = new InetSocketAddress("127.0.0.1", 6666);
            channel = SocketChannel.open(address);
            channel.configureBlocking(false);
            channel.register(selector, SelectionKey.OP_READ);
            System.out.println("user " + channel.getLocalAddress() + "上线");

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /*
     *  写数据
     */
    public void sendData(String msg) {
        ByteBuffer buffer = ByteBuffer.wrap(msg.getBytes());
        try {
            channel.write(buffer);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    /*
     * 读数据
     */
    public void readData() {
        try {
            int num = selector.select();
            if (num > 0) {
                //接收连接
                Set<SelectionKey> set = selector.selectedKeys();
                Iterator<SelectionKey> it = set.iterator();

                //处理连接
                while (it.hasNext()) {

                    SelectionKey key = it.next();
                    it.remove();

                    if (key.isReadable()) {
                        //接收服务器消息
                        SocketChannel socketChannel = (SocketChannel) key.channel();
                        ByteBuffer buffer = ByteBuffer.allocate(1024);
                        socketChannel.read(buffer);
                        String msg =new String (buffer.array());
                        System.out.println(msg);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        final ChatClient chatClient=new ChatClient();
        new Thread(){
            public void run(){
                while (true){
                    chatClient.readData();
                    try {
                        Thread.currentThread().sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                }
            }
        }.start();
        //处理用户输入
        Scanner scanner=new Scanner(System.in);
        while(scanner.hasNextLine()){
            String str=scanner.next();
            chatClient.sendData(str);
        }

    }
}

演示一下

服务器:
server
俩用户:
在这里插入图片描述

在这里插入图片描述
发消息:
发消息用户角度
在这里插入图片描述
另一个用户
在这里插入图片描述
服务器:
在这里插入图片描述
下线
在这里插入图片描述

这种项目综合三个重难点,难度和益处都是挺发大的 ,希望大家能从中受益

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值