多线程Java聊天室

实现聊天室应该将内容分为两个模块,客户端模块和服务器模块;
一.服务端创建
1.1 ServletSocket,并绑定端口号;

 ServerSocket serverSocket  = new ServerSocket(6320);
 System.out.println("服务器启动 "+ serverSocket.getLocalSocketAddress());

1.2 创建一个存储连接用户的线程池
为了使连接上的客户都创建一个线程,为了不创建多余线程使用线程池循环使用,线程数量通过拟定同时在线最大数量决定,通过循环不停监听是否有用户接入,并创建线程,通过复用拥有Runnable接口的HandClient类处理业务;

 ExecutorService executorService =
                    Executors.newFixedThreadPool(25);
                    
            while(true){
                Socket client = serverSocket.accept();
                System.out.println("有客户端连接到服务器"+client.getRemoteSocketAddress());
                executorService.execute(new HandClient(client));
            }

二.客户端创建
2.1创建Socket连接,本地与服务器

Socket client = new Socket("127.0.0.1",6320);

2.2将客户端的接收和发送信息分为两个线程,因为是两个不同的业务逻辑,而且不需要多余线程,所以用继承Thread的方式实现两个线程

new ReadData(client).start();
new WriteData(client).start();

三.具体类实现
3.1聊天室实现功能

3.1.1利用命令行的交互式输入输出,需要服务端能够进行一下操作:
1.在服务端进行注册和登录;
2.客户端通过服务端可以和在线所有客户发起群聊
3.通过服务端和指定客户进行私聊

3.1.2利用命令行的交互式输入输出,需要服务端能够进行一下操作:
1.对服务端进行输入
2.接收服务端返回数据
3.收到退出命令关闭服务端

3.2HandClient实现
3.2.1
HandClient就是对具体事务的实现,首先要拥有一个统计在线所有接收到的Socket类对象,利用ConcurrentHashMap<String,Socket>实现,String用于存储用户名利用Map的Key不能重复原则,禁止取相同用户名;
HandClient还拥有一个记录当前Socket对象的属性client;
注册时加入Map,用户退出时取出

private static final Map<String, Socket> ONLINE_CLIENT_MAP =
            new ConcurrentHashMap<>();

private final Socket client;

3.2.2
通过对客户端发送过来的字符串进行拆解,分析得到此时服务端应该进行的操作,以下是字符串格式以及处理

 @Override
    public void run() {

        try {
            InputStream clientInput = client.getInputStream();
            Scanner scanner = new Scanner(clientInput);

            /*
            消息按行读取
            1.register:<username>  例如:register:张三                        注册
            2.groupChat:<message>   例如:groupChat:大家好                    群聊
            3.privateChat:<username>:<message> 例如:privateChat:张三:你好    私聊
            4.bye                                                           退出
             */
            while (true) {
                String date = scanner.nextLine();
                if (date.startsWith("register:")) {
                    //注册
                    String username = date.split(":")[1];
                    register(username);
                    continue;
                }
                if (date.equals("bye")) {
                    //退出
                    bye();
                    break;
                }
                if (date.startsWith("groupChat:")) {
                    String message = date.split(":")[1];
                    groupChat(message);
                    continue;
                }

                if (date.startsWith("privateChat:")) {
                    String[] segment = date.split(":");
                    String targetUser = segment[1];
                    String message = segment[2];
                    privateChat(targetUser, message);
                    continue;
                }

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

以上是HandClient主要思路,具体程序https://github.com/zjgyjd/JavaLearn/blob/master/chat-room/chat-room-server/src/com/github/zjgyjd/server/mul/HanderClient.java

3.3客户端实现
客户端暂时只实现接收和发送数据
3.3.1接收服务器返回字符

package com.github.zjgyjd.client.mul;

import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.util.Scanner;

public class ReadData extends Thread {
    private final Socket client;

    public ReadData(Socket client) {
        this.client = client;
    }

    @Override
    public void run() {
        try {
            InputStream message = client.getInputStream();
            Scanner scanner = new Scanner(message);
            while (true) {
                String m = scanner.nextLine();
                if (!m.equals("bye")) {
                    System.out.println(m);
                }else{
                    this.client.close();
                    break;
                }
            }

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

3.3.2向服务器发送字符

package com.github.zjgyjd.client.mul;

import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.Scanner;

public class WriteData extends Thread {
    private final Socket client;

    public WriteData(Socket client) {
        this.client = client;
    }


    @Override
    public void run() {
        try {
            OutputStream clientOutput = this.client.getOutputStream();
            OutputStreamWriter writer = new OutputStreamWriter(clientOutput);
            Scanner scanner = new Scanner(System.in);
            while(true){
                String data = scanner.nextLine();
                writer.write(data+"\n");
                writer.flush();
                if(data.equals("bye")){
                    break;
                }

            }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值