WebSocket简易多人聊天室代码分享

	近期上课学习了socket的一些简单使用,不满足老师讲解单个客户端与服务端之间相互交流的案例,便根据过往所学的相关知识写出了这个简易的多人聊天室.若存在不足指出有待改进,还望各位大佬不吝赐教,不胜感激
package com.dgk1024.web5;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 基于TCP协议的服务器端开发
 * 1. 创建ServerSocket,并指定端口号
 * 2. 调用accept(),接收客户端请求
 * 3. 获取输入流,读取客户端发送的数据
 * 4. 获取输出流,发送数据给客户端
 * 5. 关闭释放资源
 * @author dgk1024
 * @date 2020/7/2 22:37
 */
public class TcpServer {
    /**端口号*/
    private static final int PORT = 7777;
    /**编码*/
    private static final String CHAR_SET = "utf-8";
    /**线程池连接数*/
    private static final int MAX = 20;

    public static void main(String[] args) throws IOException {
        /**0. 创建线程池*/
        ExecutorService executorService = Executors.newFixedThreadPool(MAX);
        /**1. 创建ServerSocket,并指定端口号(负责监听,三次握手)*/
        ServerSocket listener = new ServerSocket(PORT);
        System.out.println("服务器启动...");
        while(true){
            /**2. 调用accept(),接收客户端请求,阻塞方法(如果没有客户端请求则阻塞)*/
            Socket socket = listener.accept();
            /**3. 获取响应的输出流保存*/
            BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(),CHAR_SET));
            /**4. 加入map集合*/
            Group.users.put(socket,bufferedWriter);
            /**5. 从线程池获取线程处理该用户操作*/
            executorService.submit(new SocketRunnableImpl(socket));
        }
    }
}
package com.dgk1024.web5;

import java.io.*;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author dgk1024
 * @date 2020/7/3 8:32
 */
public class SocketRunnableImpl implements Runnable{
    private static final SimpleDateFormat time = new SimpleDateFormat("HH时mm分ss秒  ");
    private Socket socket=null;
    /**
     * 构造方法
     * @param socket
     */
    public SocketRunnableImpl(Socket socket){ this.socket = socket; }

    /**
     * 监听客户端是否有发送消息
     * 若有消息则发送给聊天室成员
     * 且提示发送者消息发送成功
     */
    @Override
    public void run() {
        /**
         * 用户加入后在服务端控制台发送提醒消息
         * 给聊天室其余成员发送提醒
         */
        System.out.println(time.format(new Date())+"用户"+socket.getPort()+": 进来了");
        for (Socket socket:Group.users.keySet()){
            if(socket!=this.socket){
                BufferedWriter bufferedWriter =Group.users.get(socket);
                /**非本人则发送提醒*/
                try {
                    bufferedWriter.write(time.format(new Date())+"用户"+socket.getPort()+": "+"加入群聊");
                    bufferedWriter.newLine();
                    bufferedWriter.flush();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        BufferedReader bufferedReader = null;
        try {
            bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream(),"utf-8"));
        } catch (IOException e) {
            e.printStackTrace();
        }

        while(true){
            try {
                String message = null;
                if((message = getMessage(bufferedReader))!=null){
                    sendMessage(message);
                    if("退出群聊".equals(message)){
                        /**
                         * 若用户退出群聊,结束该进程
                         */
                        break;
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 获取客户端发送的信息
     * @param bufferedReader 用户的字符输入流
     * @return 用户发送的信息
     * @throws IOException
     */
    public String getMessage(BufferedReader bufferedReader) throws IOException {
        String message = bufferedReader.readLine();
        if("退出群聊".equals(message)){
            /**
             * 若用户退出群聊
             * 交给removeUser进行后继处理
             */
            removeUser();
            System.out.println(time.format(new Date())+"用户"+socket.getPort()+": "+message);
            return "退出群聊";
        }
        if(!("".equals(message))){
            System.out.println(time.format(new Date())+"用户"+socket.getPort()+": "+message);
            return message;
        }
        return null;
    }

    /**
     * 转发用户发送的信息给聊天室所有成员(不包含自己)
     * @param message 需要转发给聊天室成员的信息
     * @throws IOException
     */
    public void sendMessage(String message) throws IOException {
        for (Socket socket:Group.users.keySet()){
            /**判断是不是本人*/
            BufferedWriter bufferedWriter =Group.users.get(socket);
            if(socket!=this.socket){
                /**非本人则发送消息*/
                bufferedWriter.write(time.format(new Date())+"用户"+socket.getPort()+": "+message);
            }else{
                /**本人则提示发送成功*/
                bufferedWriter.write("消息成功发送");
            }
            bufferedWriter.newLine();
            bufferedWriter.flush();
        }
    }

    /**
     * 给客户端发送消息退出群聊消息
     * 服务端释放相关资源
     * 客户端接收退出群聊消息会结束循环状态,进而释放资源
     * @throws IOException
     */
    public void removeUser() throws IOException {
        BufferedWriter bufferedWriter =Group.users.get(socket);
        bufferedWriter.write("你已退出群聊");
        bufferedWriter.newLine();
        bufferedWriter.flush();
        Group.users.get(socket).close();
        socket.close();
        Group.users.remove(socket);
    }
package com.dgk1024.web5;

import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;

/**
 * 基于TCP客户端开发
 * 1. 创建一个客户端套接字,并指定服务器地址和端口号
 * 2. 获取输出流,发送数据给服务器
 * 3. 获取输入流,读取服务器回复数据
 * 4. 关闭释放资源
 * @author dgk1024
 * @date 2020/7/2 23:22
 */
public class TcpClient{
    private static String HOST;
    static {
        try {
            HOST = InetAddress.getLocalHost().getHostAddress();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
    }

    private static final int PORT = 7777;
    private static final String CHAR_SET = "utf-8";

    public static void main(String[] args) throws IOException {
        // 1. 创建一个客户端套接字,并指定服务器地址和端口号
        Socket socket = new Socket(HOST,PORT);
        // 2. 获取输入输出流
        OutputStream outputStream = socket.getOutputStream();
        BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream,CHAR_SET));
        InputStream inputStream = socket.getInputStream();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream,CHAR_SET));
        /**
         * 匿名内部类
         * 监听是否有消息返回
         * 先判断消息是否为空
         */
        new Thread(()->{
            while(true){
                try {
                    String message = bufferedReader.readLine();
                    if(message!=null) {
                        if ("你已退出群聊".equals(message)) {
                            System.out.println(message);
                            // 4. 关闭释放资源
                            bufferedReader.close();
                            bufferedWriter.close();
                            socket.close();
                            break;
                        }
                        System.out.println(message);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        /**
         * 用于发送信息
         */
        while(true){
            String message = new Scanner(System.in).nextLine();
            bufferedWriter.write(message);
            bufferedWriter.newLine();
            bufferedWriter.flush();
            if("退出群聊".equals(message)){
                break;
            }
        }
    }
}
package com.dgk1024.web5;


import java.io.BufferedWriter;
import java.net.Socket;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 聊天室
 * @author dgk1024
 * @date 2020/7/3 16:29
 */
public class Group {
    /**
     * key: Socket用户
     * Value: 对应的输出流
     */
    public static ConcurrentHashMap<Socket, BufferedWriter> users = new ConcurrentHashMap<>();
    private Group(){}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值