BIO多人聊天室

2 篇文章 0 订阅

本篇文章,我主要讲解BIO的多人聊天室

BIO编程模型

服务器端设计:首先有一个accept做一个接收的工作,用主线程来接收。(创建服务端和客户端的连接)在服务器中创建线程负责与客户端进行读写服务,也就是handler线程。为了让服务器可以接收多个客户端发送过来的请求,并且和多个客户端进行交流,我们的主线程为每一个客户端创建一个与之对应的handler线程,一对一的关系。因为这是一个多人聊天室,所以,我们需要存储目前在线的用户集合
客户端设计:可以和服务器建立连接进行数据交换,接收客户文本输入(阻塞)是一个等待的过程,客户端还是需要两条线程的,一条使用户自己输入,一条是转发其他用户的消息

在这里插入图片描述

在服务器方面

在这里插入图片描述

ChatServer

//监听客户端发起的连接要求,有就接收
public class ChatServer {
    private int DEFAULT_PORT=8888;
    private final String QUIT="quit";
	
	//线程池
    private ExecutorService executorService;

    private ServerSocket serverSocket;
    //向其他客户端写消息
    private Map<Integer, Writer> connectedClients;

    public ChatServer(){
        connectedClients=new HashMap<>();
        executorService= Executors.newFixedThreadPool(10);
    }

//添加用户
    public synchronized void addClient(Socket socket) throws IOException {
        if(socket!=null)
        {
            int port=socket.getPort();
            BufferedWriter writer=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            connectedClients.put(port,writer);
            System.out.println("这个客户端["+port+"]已连接到服务器");
        }
    }

//移除用户
    public synchronized void removeClient(Socket socket) throws IOException {
        if(socket!=null)
        {
            int port=socket.getPort();
            if(connectedClients.containsKey(port)){
                connectedClients.get(port).close();
            }
            connectedClients.remove(port);
            System.out.println("这个客户端["+port+"]已断开连接");
        }
    }

//转发消息
    public synchronized void forwardMessage(Socket socket,String msg) throws IOException {
        for(Integer id:connectedClients.keySet())
        {
            if(!id.equals(socket.getPort()))
            {
                Writer writer=connectedClients.get(id);
                writer.write(msg);
                writer.flush();
            }
        }
    }

//查看是否退出
    public boolean readToQuit(String msg)
    {
        return msg.equals(QUIT);
    }
//统一关闭方法
    public synchronized void close(){
        if(serverSocket!=null)
        {
            try {
                serverSocket.close();
                System.out.println("关闭serverSocket");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

//开始
    public void start(){

        try {
            //绑定监听端口
            serverSocket=new ServerSocket(DEFAULT_PORT);
            System.out.println("服务器已经启动,监听端口"+DEFAULT_PORT);
            while (true)
            {
                //等待客户端连接
                //accept的调用是阻塞式的,一旦有连接就会返回连接的socket
                Socket socket=serverSocket.accept();
                //创建charHandler线程
                //new Thread(new ChatHandler(this,socket)).start();
                executorService.execute(new ChatHandler(this,socket));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            close();
        }
    }

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

ChatHandler

public class ChatHandler implements Runnable{
    private ChatServer server;
    private Socket socket;

    public ChatHandler(ChatServer server,Socket socket){
        this.server=server;
        this.socket=socket;
    }


    @Override
    public void run() {
        try {
            //存储新上线客户
            server.addClient(socket);

            //读取用户发送来的消息
            BufferedReader reader=new BufferedReader(new InputStreamReader(socket.getInputStream()));

            String msg=null;
            while ((msg=reader.readLine())!=null)
            {
                String fwgMsg="客户端["+socket.getPort()+"]"+msg+"\n";
                System.out.println(fwgMsg);
                //转发消息给聊天室在线的用户
                server.forwardMessage(socket,fwgMsg);

                //检查用户发送的消息是不是准备退出
                if(server.readToQuit(msg))
                {
                    break;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                server.removeClient(socket);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

在客户端方面

在这里插入图片描述

ChatClient

public class ChatClient {

    private final String DEFAULT_SERVER_HOST="127.0.0.1";
    private final int DEFAULT_SERVER_PORT=8888;
    private final String QUIT="quit";


    private Socket socket;
    private BufferedReader reader;
    private BufferedWriter writer;


    //发送消息给服务器
   public void send(String msg) throws IOException {
       if(!socket.isOutputShutdown())
       {
           writer.write(msg+"\n");
           writer.flush();
       }
   }

   //从服务器接收消息
    public String receive() throws IOException {
       String msg=null;
       if(!socket.isInputShutdown())
       {
           msg=reader.readLine();
       }
       return msg;
    }

    //检查用户是否准备退出
    public boolean readyToQuit(String msg)
    {
        return msg.equals(QUIT);
    }

    public void close()
    {
        if(writer!=null)
        {
            try {
                System.out.println("关闭socket");
                writer.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public void start()
    {
        try {
            //创建socket对象
            socket=new Socket(DEFAULT_SERVER_HOST,DEFAULT_SERVER_PORT);
            //创建发送和接收消息的io流
            reader=new BufferedReader(new InputStreamReader(socket.getInputStream()));
            writer=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));

            //处理用户输入
            new Thread(new UserInputHandler(this)).start();
            //读取服务器转发的消息
            String msg=null;
            while((msg=receive())!=null){
                System.out.println(msg);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            close();
        }
    }

    public static void main(String[] args) {
        ChatClient client=new ChatClient();
        client.start();
    }
}

UserInputHandler

public class UserInputHandler implements Runnable{


    private ChatClient chatClient;

    public UserInputHandler(ChatClient chatClient){
        this.chatClient=chatClient;
    }

    @Override
    public void run() {
        //等待用户输入消息
        BufferedReader consoleReader=new BufferedReader(new InputStreamReader(System.in));
        try {
            while (true) {

                String input = consoleReader.readLine();

                //向服务器发送消息
                chatClient.send(input);
                //检查用户是否准备退出
                if(chatClient.readyToQuit(input))
                {
                    break;
                }

            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值