Java实现ChatRoom

基于连接通信Socket、多线程的Java聊天室

1、开发环境:

IDEA2018.1+JDK1.8

2、实现功能:

实现了模拟登录注册、群聊、私聊、显示当前在线人数列表;

在发送信息时,会向对方发送者及显示发送时间;

显示在线人数列表时,也会显示查询时间;

实现了多线程发送消息、接收消息过程。

3、代码解析(源码可见本篇博客最后):

1)客户端源码解析

客户端使用两个线程操作

一个读线程:创建客户端输入流,while循环将读到的信息输出道控制台,模拟一直等待监听输入的情况;

一个写线程:创建客户端输出流,while循环获取用户从控制台输入的内容,若用户输入的信息中包含"bye",则关闭流并且关闭该用户的Socket,此时退出while循环,写线程结束;此时读线程的if条件判断就会执行break;while循环停止,读线程结束。

2)服务器源码解析

利用Executors类创建固定大小为20的线程池(实现多线程);

使用Map集合来存储用户信息,<String, Socket>:用户名,客户端的socket;Map集合使用子类ConcurrentHashMap来实例化,保证线程安全(主要可见Java集合总结);

使用内部类来处理客户端的连接与发送信息;

根据控制台约束信息进行用户注册、私发、群聊等等功能的实现

3)两台计算机之间使用套接字建立TCP连接过程

服务器实例化一个ServerSocket对象,new ServerSocket(6666):表示是通过服务器上的6666端口进行通信;

服务器调用ServerSocket类的accept(),该方法阻塞式等待客户端的连接;

客户端实例化一个Socket对象,new Socket("127.0.0.1", 6666):指定服务器名称和端口号来请求连接,该构造方法试图将客户端连接到指定的服务器和端口号,如果通信建立,则会在客户端创建Socket对象能够与服务器进行通信;

在服务端,accept()方法返回客户端的socket对象。

4、结果展示:

开启了三个客户端

测试:   用户上线功能、显示当前用户列表功能、私聊功能、用户下线功能

客户端3

测试:   用户上线功能、显示当前用户列表功能、群聊功能

客户端2

测试:   用户上线功能、显示当前用户列表功能、群发功能、私聊功能

客户端1

服务端:体现出了用户上线及用户下线的情况

服务端

客户端源代码:

//读线程
class ReadThread implements Runnable{
    private Socket client;

    public ReadThread(Socket client) {
        this.client = client;
    }
    @Override
    public void run() {
        try{
            Scanner in = new Scanner(client.getInputStream());
            while(true){
                if(in.hasNextLine()){
                    System.out.println(in.nextLine());
                }
                if(client.isClosed()){
                    break;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

//写线程
class WriteThread implements Runnable{
    private Socket client;

    public WriteThread(Socket client) {
        this.client = client;
    }
    @Override
    public void run() {
        try {
            PrintStream out = new PrintStream(client.getOutputStream(),
                    true, "UTF-8");
            Scanner scanner = new Scanner(System.in);
            String str = "";
            while(true){
                System.out.println("在此输入:");
                if(scanner.hasNextLine()){
                    str = scanner.nextLine();
                    out.println(str);
                }
                if(str.contains("bye")){
                    scanner.close();
                    out.close();
                    client.close();
                    break;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

public class MutilThreadClient {
    public static void main(String[] args) {
        try {
            Socket client = new Socket("127.0.0.1", 6666);
            Thread readThread = new Thread(new ReadThread(client));
            Thread writeThread = new Thread(new WriteThread(client));
            readThread.start();
            writeThread.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

服务器源代码:

public class MutilThreadServer {
    //使用Map的K,V存储用户信息(用户名,socket),模拟登陆现象
    private static Map<String, Socket> clientMap = new ConcurrentHashMap<String, Socket>();//线程安全
    //内部类,处理客户端
    private static class ExecuteClient implements Runnable{
        private Socket client;
        private ExecuteClient(Socket client) {
            this.client = client;
        }//构造注入客户端socket
        //返回给客户端信息时间
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        @Override
        public void run() {
            try {
                //获取输入流
                Scanner in = new Scanner(client.getInputStream());
                String str = "";
                while(true){
                    if(in.hasNextLine()){
                        str = in.nextLine();

                        //windows下将默认的换行\r\n中的\r替换为空字符串
                        Pattern pattern = Pattern.compile("\r");
                        Matcher matcher = pattern.matcher(str);
                        str = matcher.replaceAll("");

                        //聊天室实现的功能
                        //用户上线:
                        // user:123
                        if(str.startsWith("user")){
                            String user = str.split("\\:")[1];
                            register(user, client);
                            continue;
                        }
                        //群聊:
                        // G:发送内容
                        if(str.startsWith("G")){
                            String text = str.split("\\:")[1];
                            String user = getUser(client);
                            if(user == ""){
                                continue;
                            }
                            groupChat(text, user);
                            continue;
                        }
                        //私聊
                        //P-sendUser:text
                        if(str.startsWith("P")){
                            String sendUser = str.split("\\-")[1]
                                    .split("\\:")[0];
                            String text = str.split("\\-")[1]
                                    .split("\\:")[1];
                            String user = getUser(client);
                            if(user == ""){
                                continue;
                            }
                            privateChat(sendUser, text, user);
                            continue;
                        }
                        //查看当前用户在线列表
                        //用户输入ls:显示当前在线人数
                        if(str.equals("ls")){
                            PrintStream out = new PrintStream(client.getOutputStream(),
                                    true, "UTF-8");
                            out.println("当前在线用户列表如下  " + sdf.format(System.currentTimeMillis()));
                            for(String key : clientMap.keySet()){
                                out.println(" · 用户" + key);
                            }
                            out.println(" · 当前在线人数:" + clientMap.size());
                            continue;
                        }
                        //用户下线
                        if(str.contains("bye")){
                            String user = getUser(client);
                            System.out.println("用户" + user + "下线了.....");
                            clientMap.remove(user);
                            continue;
                        }
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        //通过客户端socket获取用户名
        private String getUser(Socket client) {
            String user = "";
            for(String key : clientMap.keySet()) {
                if (clientMap.get(key).equals(client)) {
                    user =  key;
                }
            }
            if(user == ""){
                try {
                    PrintStream out = new PrintStream(client.getOutputStream(),
                            true, "UTF-8");
                    out.println("当前您还未注册,请先注册!");
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return user;
        }
        //注册实现
        private void register(String user, Socket client) {
            System.out.println("用户"+user+"上线了.......");
            clientMap.put(user, client);
            System.out.println("当前群聊人数为" + clientMap.size() + "人");
            //告知用户注册成功
            try {
                PrintStream out = new PrintStream(client.getOutputStream(),
                        true, "UTF-8");
                out.println("注册成功!");

            } catch (IOException e) {
                System.err.println("注册异常:" + e);
            }
        }
        //群聊实现
        private void groupChat(String text, String user) {
            Set<Entry<String, Socket>> clientSet = clientMap.entrySet();
            for (Entry<String, Socket> entry : clientSet) {
                try {
                    PrintStream out = new PrintStream(entry.getValue().getOutputStream(),
                            true, "UTF-8");
                    out.println("用户" + user + "  " + sdf.format(System.currentTimeMillis()));
                    out.println("   群发:" + text);
                } catch (IOException e) {
                    System.err.println("群聊异常:" + e);
                }
            }
        }
        //私聊实现
        private void privateChat(String sendUser, String text, String user) {
            try {
                PrintStream out = new PrintStream(clientMap.get(sendUser).getOutputStream(),
                        true, "UTF-8");
                out.println("用户" + user + "  " + sdf.format(System.currentTimeMillis()));
                out.println("   私发:"+ text);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws Exception{
        //利用Exectors工具类创建固定大小线程池
        ExecutorService executorService = Executors.newFixedThreadPool(20);
        //创建服务端Socket
        ServerSocket serverSocket = new ServerSocket(6666);
        for(int i = 0; i < 20; ++i){
            System.out.println("等待客户端链接.........");
            Socket client = serverSocket.accept();
            System.out.println("有新的客户端连接,端口号为" + client.getPort());
            //向线程池提交线程
            executorService.submit(new ExecuteClient(client));
        }
        executorService.shutdown();
        serverSocket.close();
    }
}

 整体概括

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值