Java项目之多线程聊天室(客户端以及服务端)

package com.company;

import java.io.IOException;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.sql.SQLOutput;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 多线程聊天室服务器端
 */


public class MultiThreadServer {
    //存储所有的注册的客户端
    private static Map clientMap = new ConcurrentHashMap();

    //具体处理与每一个客户端通信的内部类
    private static class ExecuteClient implements Runnable {
        private Socket client;

        private ExecuteClient(Socket client) {
            this.client = client;
        }

        @Override
        public void run() {

            try {
                //获取客户端输入流
                Scanner in = new Scanner(client.getInputStream());
                String strFromClient;
                while (true) {
                    if (in.hasNextLine()) {
                        strFromClient = in.next();
                        //windows下默认的换行符为\r\n
                        //使用正则表达式将默认换行符替换为\n
                        Pattern pattern = Pattern.compile("\r"); //匹配对应的“\r”字符
                        Matcher matcher = pattern.matcher(strFromClient);//返回被比较的对象strFromClient
                        strFromClient = matcher.replaceAll(" ");//替换strFromClient中的”\r"为空格“ ”
                        //用户注册
                        if(strFromClient.startsWith("userName")){
                            String userName=strFromClient.split("\\:")[1];
                            registerUser(userName,client);
                            continue;
                        }
                        //群聊流程
                        if(strFromClient.startsWith("G")){
                            String msg=strFromClient.split("\\:")[1];
                            groupChat(msg);
                            continue;
                        }
                        //私聊流程
                        if(strFromClient.startsWith("P")){
                            String userName=strFromClient.split("\\:")[1]
                                    .split("\\-")[0];
                            String msg=strFromClient.split("\\:")[1]
                                    .split("\\-")[1];
                            privateChat(userName,msg);
                        }
                        //用户退出
                        if(strFromClient.equals("byebye")){
                            String usename=null;
                            for(String keyName:clientMap.keySet()){
                                if(clientMap.get(keyName).equals(client)){
                                    usename=keyName;
                                }
                            }
                            System.out.println("用户:"+usename+"下线了");
                            System.out.println("当前用户人数为"+(clientMap.size()-1)+"人");
                            clientMap.remove(usename);
                            continue;
                        }
                    }
                }
            } catch (IOException e) {
                System.out.println("服务器通信异常,异常为:"+e);
            }
        }


    //用户注册
    private void registerUser(String userName, Socket client) {
        System.out.println("用户名为:" + userName);
        System.out.println("用户" + userName + "上线啦");
        System.out.println("当前群聊人数为:" + (clientMap.size() + 1 )+ "人");
        //将用户信息保存到clientMapzhong
        clientMap.put(userName, client);
        try {
            //取得对应用户的输出流
            PrintStream out = new PrintStream(client.getOutputStream(),
                    true, "utf-8");
            //告诉用户注册成功
            out.println("用户注册成功!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //群聊流程
    private void groupChat(String msg) {
        //取出当前所有的用户端口,发送群消息
        Set> clientSet = clientMap.entrySet();
        for (Map.Entry entry : clientSet) {
            //取得用户端口
            Socket socket = entry.getValue();
            try {
                //取得用户的输出流
                PrintStream out = new PrintStream(socket.getOutputStream(),
                        true, "utf-8");
                //通过输出流向用户发送消息
                out.println("群聊消息为:" + msg);
            } catch (IOException e) {
                System.out.println("群聊异常,错误为:" + e);
            }
        }
    }
//私聊流程
    private void privateChat(String userName, String msg) {
        //在注册表中查找对应的用户的socket
        Socket privateSocket = clientMap.get(userName);
        try {
            //获取指定用户的输出流
            PrintStream out = new PrintStream(privateSocket.getOutputStream(),
                    true, "utf-8");
            //向指定用户发送消息
            out.println("私聊消息为"+msg);
        } catch (IOException e) {
            System.out.println("私聊异常,错误为:" + e);
        }
    }

}

    public static void main(String[] args) throws IOException {
        //创建一个定长为20的线程池
        ExecutorService executorService= Executors.newFixedThreadPool(20);
        //绑定本地ip,定制端口号
        ServerSocket serverSocket=new ServerSocket(9999);
        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();
    }
}
 

 

聊天室客户端:

import javax.lang.model.util.SimpleAnnotationValueVisitor6;
import java.io.IOException;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;

/**
 * 读取服务器发来的消息线程
 */
class ReadFromServerThread implements Runnable{
    private  Socket client;
    public ReadFromServerThread (Socket client) {
        this.client=client;
    }

    @Override
    public void run() {
        try {
            //获取客户端输入流
            Scanner in=new Scanner(client.getInputStream());
            in.useDelimiter("\n");
            while(true){
                if(in.hasNextLine()){
                    System.out.println("当前收到服务器转发的消息"+in.next());
                }
                //此客户端退出
                if(client.isClosed()){
                    System.out.println("客户端已关闭"+client.getPort()); // 输出关闭的端口号
                    break;
                }
            }
            in.close();

        } catch (IOException e) {
            System.out.println("客户端读线程异常,错误为:"+e);
        }
    }
}

/**
 * 将消息发送给服务器
 */
class WriteToServerThread implements Runnable{
    private Socket client;

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

    @Override
    public void run() {
        try {
            //获取客户端输入流,从键盘输入
            Scanner scanner=new Scanner(System.in);
            scanner.useDelimiter("\n");
            //获取客户端输出流,将消息发送给服务器
            PrintStream out=new PrintStream(client.getOutputStream());
            while(true){
                System.out.println("请输入要发送的消息:");
                String strToServer;
                if(scanner.hasNextLine()){
                    strToServer=scanner.nextLine().trim();
                    out.println(strToServer);
                    //客户端退出标志
                    if(strToServer.equals("byebye")){
                        System.out.println("关闭客户端");
                        scanner.close();
                        out.close();
                        client.close();
                        break;
                    }
                }
            }
        } catch (IOException e) {
            System.out.println("客户端写线程异常,发生的错误为:"+e);
        }

    }
}


/**
 * 多线程的聊天室客户端
 */

public class MultiThreadClient {
    public static void main(String[] args) {
        try {
            //连接指定端口
            Socket client=new Socket("127.0.0.1",9999);
            //读取服务器消息线程
            Thread readFromSever=new Thread(new ReadFromServerThread(client));
            //写入消息给服务器线程
            Thread writeToServer=new Thread(new WriteToServerThread(client));
            //启动线程
            readFromSever.start();
            writeToServer.start();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}
 

 

你可能感兴趣的:(Java项目之多线程聊天室(客户端以及服务端))