前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java实现无界面控制台版聊天室

Java实现无界面控制台版聊天室

作者头像
HcodeBlogger
发布2020-07-14 10:08:58
1.3K0
发布2020-07-14 10:08:58
举报
文章被收录于专栏:Hcode网站Hcode网站

前言

今天带来的是利用JAVA制作一个简易无GUI的纯控制台聊天室。 实现原理:简易TCP网络编程实现客户端与服务器的交流,IO流读写数据,多线程实现多人交流。

具体用途

(××为指定用户或管理员名字) ①普通用户功能:可以聊天室群聊,一对一的私聊(使用@××>); ②管理员功能:可以利用#××进行踢人,*广告*发送广告,*广告>修改默认的广告内容

步骤

① 首先是实现登陆验证的服务器端

用的是java.net包里面的ServerSocket创建服务器端口,且设定了管理员特定密码,以及聊天室的普通用户的通用密码 需要开启多线程 一个线程应付一个客户端

代码语言:javascript
复制
package cn.Himit_ZH.ServerLogin;

import cn.Himit_ZH.ServerLogin.CloseUtils;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Random;

/**
 * 名字:登陆验证服务器
 * 用途:实现验证登陆,判断是否为管理员。
 * 步骤:
 * 创建服务器
 * 1、指定端口 使用ServerSocket创建服务器
 * 2、阻塞式等待连接 accept
 * 3、操作: 输入输出流操作
 * 4、释放资源
 * IO流实现数据的对接
 * 
 * @author Himit_ZH
 *
 */
public class ChatRoomLoginServer {
    private static String RoomPwd = "666";//普通用户进入聊天室的密码
    private static String AdminPWd = "admin";//管理员进入聊天室的密码
    public static void main(String[] args) throws IOException {
        System.out.println("-----The login Server-----");
        // 1、指定端口 使用ServerSocket创建服务器
        ServerSocket server =new ServerSocket(61111);
        boolean isRunning =true;;
        // 2、阻塞式等待连接 accept
        while(isRunning) {
            Socket client =server.accept();
            System.out.println("-----一个客户端建立了连接-----");
            new Thread(new Channel(client)).start();
        }
        server.close();
    }
    //一个channel就代表一个客户端
    static class Channel implements Runnable{
        private Socket  client;
        //输入流
        private DataInputStream dis;
        //输出流
        private DataOutputStream dos;
        private boolean IsAdmin;
        public Channel(Socket  client) {
            this.client = client;
            this.IsAdmin = false;
            try {
                //输入
                dis = new DataInputStream(client.getInputStream());
                //输出
                dos =new DataOutputStream(client.getOutputStream());
            } catch (IOException e) {
                e.printStackTrace();
                CloseUtils.close(dos,dis);
            }

        }

        // 判断是否为管理员
        public boolean isAdmin() {
            return IsAdmin;
        }

        //接收数据
        private String receive() {
            String datas ="";
            try {
                datas = dis.readUTF();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return datas;
        }

        //发送数据
        private void send(String msg) {
            try {
                dos.writeUTF(msg);
                dos.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        @Override
        public void run() {
            // 3、操作: 输入输出流操作
            String uname ="";
            String upwd ="";
            //数据分析
            String[] dataArray = receive().split("&");
            for(String info:dataArray) {
                String[] userInfo =info.split("=");
                if(userInfo[0].equals("uname")) {
                    System.out.println("用户名为:"+userInfo[1]);
                    uname = userInfo[1];
                }else if(userInfo[0].equals("upwd")) {
                    System.out.println("聊天室的密码为:"+userInfo[1]);
                    upwd = userInfo[1];
                }
            }
            if (uname.contains("admin")&&upwd.equals(AdminPWd)){
                send("TRUE_ADMIN");//验证为管理员
                this.IsAdmin = true;
            }
            else {
                if (upwd.equals(RoomPwd)) { //成功
                    send("TRUE_USER");//验证为普通用户
                } else { //失败
                    send("FALSE");
                }
            }
            CloseUtils.close(client,dos,dis);

        }

    }

}

②第二是识别管理员指令和转发用户内容的中转服务器

具体作用:根据指令转发私聊,群聊,实现踢人,发广告,修改广告内容,服务器实现监控连接 需要开启多线程 一个线程应付一个客户端

代码语言:javascript
复制
package cn.Himit_ZH.ServerTransponder;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.CopyOnWriteArrayList;


/**
 * 名字: 指令识别和内容中转服务器
 * 作用: 根据指令转发私聊,群聊,实现踢人,发广告,修改广告内容,服务器实现监控连接
 * 利用使用ServerSocket创建服务器
 * 阻塞式等待连接 accept
 * @author Himit_ZH
 *
 */

public class ChatRoomServer {
    private static CopyOnWriteArrayList<Channel> all = new CopyOnWriteArrayList();
    private static Map<String,String> map = new HashMap<>();
    private static String advert = "人生苦短,我用python!";
    public static void main(String[] args) throws IOException {
        System.out.println("-----The Chat Server-----");
        map.put("admin1","Himit_ZH");
        map.put("admin2","小浩");//此次添加管理员信息
        ServerSocket server = new ServerSocket(62222);

        while(true) {
            Socket client = server.accept();
            ChatRoomServer.Channel c = new ChatRoomServer.Channel(client);
            all.add(c);
            if (c.isAdmin) {
                System.out.println("-----一个客户端建立了连接--->[管理员]"+c.name+",目前服务器连接人数为:"+all.size()+"个");
            }else{
                System.out.println("-----一个客户端建立了连接--->[用户]"+c.name+",目前服务器连接人数为:"+all.size()+"个");
            }
            (new Thread(c)).start();
        }
    }

static class Channel implements Runnable {
        private DataInputStream dis;
        private DataOutputStream dos;
        private Socket client;
        private boolean isRunning;
        private String name;
        private boolean isAdmin;
        public Channel(Socket client) {
            this.client = client;
            try {
                this.dis = new DataInputStream(client.getInputStream());
                this.dos = new DataOutputStream(client.getOutputStream());
                this.isRunning = true;
                String result = this.receive();
                //判断是否为管理员
                String []results=result.split("#");
                if(results[1].equals("TRUE_ADMIN")){
                    this.isAdmin = true;
                    this.name = map.get(results[0]); //获得map容器里面的管理员对应名字
                }else {
                    this.isAdmin = false;
                    this.name = results[0];//用户名直接获取
                }
                if (this.isAdmin){
                    this.send("\t-----尊敬的管理员["+this.name+"],欢迎您的到来!-----\t\n\t-----目前聊天室总人数为:" + (String.valueOf(all.size() + 1))+"个-----\t");
                    this.send("\t-----温馨提示:使用[@××>]格式可进行私聊,使用#××可踢出对应成员-----\t");
                    this.send("\t-----温馨提示:使用[*广告*]格式可发系统广告,使用[*广告>××]可踢可修改原定广告内容--\t");
                    sendOthers("管理员[" + this.name + "]加入<相亲相爱一家人>的聊天室,请大家注意言行!", true);
                }else {
                    this.send("\t-----亲爱的用户[" + this.name + "],欢迎你的到来!-----\t\n\t-----目前聊天室总人数为:" + (String.valueOf(all.size() + 1)) + "个-----\t");
                    this.send("\t-----温馨提示:使用[@××>]格式可进行私聊-----\t");
                    sendOthers("用户[" + this.name + "]加入<相亲相爱一家人>的聊天室", true);
                }
            } catch (IOException var3) {
                System.out.println("聊天室服务器初始化失败");
                this.release();
            }

        }


private String receive() {
            String msg = "";
            try {
                msg = this.dis.readUTF();
            } catch (IOException var3) {
                this.release();
                if(this.isAdmin) {
                    System.out.println("管理员["+this.name + "]断开了与服务器的连接,目前服务器连接人数为"+all.size()+"人");
                }else{
                    System.out.println("用户["+this.name + "]断开了与服务器的连接,目前服务器连接人数为"+all.size()+"人");
                }

            }

            return msg;
        }

        private void send(String msg) {
            try {
                this.dos.writeUTF(msg);
                this.dos.flush();
            } catch (IOException var3) {
                System.out.println("服务器故障,未能成功发送消息!");
                this.release();
            }

        }

        private void sendOthers(String msg, boolean isSys) {
            char instruction = msg.charAt(0);
            boolean flag1 = false;
            boolean flag2 = false;
            int idx = msg.indexOf(">");
            if(msg.equals("*广告*")&&this.isAdmin){
                sendOthers("[广告]"+advert,true);
                return;
            }
            if (msg.indexOf("*广告>")==0&&this.isAdmin){
                advert = msg.substring(4,msg.length());
                send("\t-----系统通知:广告内容修改成功!-----\t");
                return;
            }
            if (instruction == '@'&&idx!=-1) {
                String targetName = msg.substring(1, idx);
                msg = msg.substring(idx + 1);
                for(Channel other: all) {
                    if (targetName.equals(this.name)){
                        send("\t-----系统提示:对不起,你不能私聊自己!-----\t");
                        flag1 = true;
                        break;
                    }else {
                        if (other.name.equals(targetName)) {//目标
                            if (this.isAdmin) {
                                other.send("管理员[" + this.name + "]私聊你:" + msg);
                            } else {
                                other.send("用户[" + this.name + "]私聊你:" + msg);
                            }
                            flag1=true;
                            break;
                        }
                    }
                }
                if (!flag1){
                    send("\t-----系统提示:对不起,聊天室并无["+targetName+"]用户或管理员-----\t");
                }
            }else if(instruction == '#'&&this.isAdmin){
                String targetName = msg.substring(1, msg.length());
                if (targetName.equals(this.name)){
                    send("\t-----系统提示:对不起,你不能踢出自己!-----\t");
                    flag2 = true;
                }else {
                    for (Channel other : all) {
                        if (other.name.equals(targetName)) {//目标
                            sendOthers("用户[" + other.name + "]被管理员[" + this.name + "]踢出了聊天室", true);
                            other.send("#对不起,你被管理员[" + this.name + "]踢出了聊天室!");
                            other.isRunning = false;
                            CloseUtils.close(other.dis,other.dos,other.client);//退出
                            all.remove(other);
                            flag2 = true;
                            break;
                        }
                    }
                }
 private String receive() {
            String msg = "";
            try {
                msg = this.dis.readUTF();
            } catch (IOException var3) {
                this.release();
                if(this.isAdmin) {
                    System.out.println("管理员["+this.name + "]断开了与服务器的连接,目前服务器连接人数为"+all.size()+"人");
                }else{
                    System.out.println("用户["+this.name + "]断开了与服务器的连接,目前服务器连接人数为"+all.size()+"人");
                }

            }

            return msg;
        }

        private void send(String msg) {
            try {
                this.dos.writeUTF(msg);
                this.dos.flush();
            } catch (IOException var3) {
                System.out.println("服务器故障,未能成功发送消息!");
                this.release();
            }

        }

        private void sendOthers(String msg, boolean isSys) {
            char instruction = msg.charAt(0);
            boolean flag1 = false;
            boolean flag2 = false;
            int idx = msg.indexOf(">");
            if(msg.equals("*广告*")&&this.isAdmin){
                sendOthers("[广告]"+advert,true);
                return;
            }
            if (msg.indexOf("*广告>")==0&&this.isAdmin){
                advert = msg.substring(4,msg.length());
                send("\t-----系统通知:广告内容修改成功!-----\t");
                return;
            }
            if (instruction == '@'&&idx!=-1) {
                String targetName = msg.substring(1, idx);
                msg = msg.substring(idx + 1);
                for(Channel other: all) {
                    if (targetName.equals(this.name)){
                        send("\t-----系统提示:对不起,你不能私聊自己!-----\t");
                        flag1 = true;
                        break;
                    }else {
                        if (other.name.equals(targetName)) {//目标
                            if (this.isAdmin) {
                                other.send("管理员[" + this.name + "]私聊你:" + msg);
                            } else {
                                other.send("用户[" + this.name + "]私聊你:" + msg);
                            }
                            flag1=true;
                            break;
                        }
                    }
                }

 if (!flag1){
                    send("\t-----系统提示:对不起,聊天室并无["+targetName+"]用户或管理员-----\t");
                }
            }else if(instruction == '#'&&this.isAdmin){
                String targetName = msg.substring(1, msg.length());
                if (targetName.equals(this.name)){
                    send("\t-----系统提示:对不起,你不能踢出自己!-----\t");
                    flag2 = true;
                }else {
                    for (Channel other : all) {
                        if (other.name.equals(targetName)) {//目标
                            sendOthers("用户[" + other.name + "]被管理员[" + this.name + "]踢出了聊天室", true);
                            other.send("#对不起,你被管理员[" + this.name + "]踢出了聊天室!");
                            other.isRunning = false;
                            CloseUtils.close(other.dis,other.dos,other.client);//退出
                            all.remove(other);
                            flag2 = true;
                            break;
                        }
                    }
                }
                if (!flag2){
                    send("\t-----系统提示:对不起,聊天室并无["+targetName+"]用户或管理员-----\t");
                }
            }else {
                for(Channel other: all) {
                    if(!isSys) {
                        if(other==this) { //自己
                            if(this.isAdmin) {
                                send("[管理员]自己:" + msg);
                            }else{
                                send("[用户]自己:" + msg);
                            }
                        }else {//别人
                            if (this.isAdmin) {
                                other.send("[管理员]" + this.name + ":" + msg);//群聊消息
                            } else {
                                other.send("[用户]" + this.name + ":" + msg);//群聊消息

                            }
                        }
                    }else {
                        other.send("\t-----系统通知:"+msg+"-----\t"); //系统消息
                    }
                }
            }
        }
        //释放资源
        private void release() {
            this.isRunning = false;
            CloseUtils.close(dis,dos,client);
            //退出
            all.remove(this);
            sendOthers("用户["+this.name+"]退出了聊天室",true);
        }
        @Override
        public void run() {
            while(isRunning) {
                String  msg= receive() ;
                if(!msg.equals("")) {
                    //send(msg);
                    sendOthers(msg,false);
                }
            }
        }
    }
}

③客户端

首先先验证登陆,利用TCP,IO流(当然服务器的IP都是“localhost”本机,因为你的服务器也是运行在本机上的,端口就是上面的验证登录服务器设定的端口号)往验证登陆的服务器发送用户名和密码,验证成功后会得到指令TRUE_USER(标识为普通用户)或者是TRUE_ADMIN(标识为管理员),接着中转服务器获取信息初始化,开启对应的用户线程,用户自身也开启两个线程,一个为时时传递消息的发送端线程,一个为时时接受信息的接受端线程。 《1》用户运行的程序(几个用户就启动几个程序)

代码语言:javascript
复制
package cn.Himit_ZH.Client;
import java.io.*;
import java.net.Socket;

/**
 * @Author: Himit_ZH
 * @Date: 2020/2/20 17:09
 * @Description:
 * @ProjectName:
 */
public class ChatRoomClient {
    public static boolean flag = false;
    public static void main(String[] args) throws IOException {
        String result = "";
        String uname = "";
        System.out.println("\t-----The Sign Client-----\t");
        System.out.println("\t--<相亲相爱一家人>聊天室---\t");
        while (!flag) {
            BufferedReader console = new BufferedReader(new InputStreamReader(System.in));
            System.out.print("\t     请输入昵称:");
            uname = console.readLine();
            System.out.print("\t     请输入密码:");
            String upwd = console.readLine();

            //1、建立连接: 使用Socket创建客户端 +服务的地址和端口
            Socket client1 = new Socket("localhost", 61111);
            //2、操作: 输入输出流操作
            DataOutputStream dos = new DataOutputStream(client1.getOutputStream());
            dos.writeUTF("uname=" + uname + "&" + "upwd=" + upwd);
            dos.flush();

            DataInputStream dis = new DataInputStream(client1.getInputStream());
            result = dis.readUTF();
            dos.close();
            client1.close();
            System.out.println("\t-----The Sign Client-----\t");
            if (result.equals("FALSE")){
                System.out.println("-----密码错误,请重新输入-----");
            }
            else {
                flag =true;
            }
            //3、释放资源
        }
        System.out.println("\t-----The Chat Client-----\t");
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        Socket client2 = new Socket("localhost", 62222);
        (new Thread(new Send(client2,uname,result))).start();//Thread1:向服务器发送自己的消息
        (new Thread(new Receive(client2))).start();//Thread2:接受服务器的消息(系统消息和其他网友的信息)
    }
}

《2》发送端

代码语言:javascript
复制
package cn.Himit_ZH.Client;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;

/**
 * 使用多线程封装:发送端
 * 作用:获取键盘输入的信息或者指令,往中转服务器发送信息
 * @author Himit_ZH
 *
 */
public class Send implements Runnable {
    private BufferedReader console ;
    private DataOutputStream dos;
    private Socket client;
    private boolean isRunning;
    private String name;
    private String resultOfAdmin;
    public Send(Socket client,String name,String result) {
        this.client =client;
        console =new BufferedReader(new InputStreamReader(System.in));
        this.isRunning = true;
        this.resultOfAdmin = result;
        this.name = name;
        try {
            dos =new DataOutputStream(client.getOutputStream());
            //发送名称
            send(name+"#"+resultOfAdmin);
        } catch (IOException e) {
            System.out.println("数据输出流初始化错误,请重启");
            this.release();
        }
    }
    @Override
    public void run() {
        while(isRunning) {
            String msg = getStrFromConsole();
            if(!msg.equals("")) {
                send(msg);
            }
        }
    }

    //发送消息
    private void send(String msg) {
        try {
            dos.writeUTF(msg);
            dos.flush();
        } catch (IOException e) {
            System.out.println("与服务器断开连接,消息发送失败!请重启客户端!");
            release();
        }
    }
    /**
     * 从控制台获取消息
     * @return
     */
    private String getStrFromConsole() {
        try {
            return  console.readLine();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "";
    }
    //释放资源
    private void release() {
        this.isRunning = false;
        CloseUtils.close(dos,client);
    }

}

《3》接受端

代码语言:javascript
复制
package cn.Himit_ZH.Client;


import java.io.DataInputStream;
import java.io.IOException;
import java.net.Socket;

/**
 * 使用多线程封装:接收端
 * 作用:接受中转服务器发来的信息,打印到控制台
 * @author Himit_ZH
 *
 */
public class Receive implements Runnable {
    private DataInputStream dis ;
    private Socket client;
    private boolean isRunning;
    public Receive(Socket client) {
        this.client = client;
        this.isRunning = true;
        try {
            dis =new DataInputStream(client.getInputStream());
        } catch (IOException e) {
            System.out.println("数据输入流初始化错误,请重启");
            release();
        }
    }
    //接收消息
    private String receive() {
        String msg ="";
        try {
            msg =dis.readUTF();
        } catch (IOException e) {
            System.out.println("未能成功接受到服务器的消息,请重启客户端!");
            release();
        }
        return msg;
    }



    @Override
    public void run() {
        while(isRunning) {
            String msg =receive();
            if (msg.charAt(0) =='#'){
                System.out.println(msg.substring(1,msg.length()));
                isRunning = false; //收到#指令,关闭线程
            }else {
                if (!msg.equals("")) {
                    System.out.println(msg);
                }
            }
        }
    }
    //释放资源
    private void release() {
        this.isRunning = false;
        CloseUtils.close(dis,client);
    }

}

④最后一个是三个运行程序都要用的工具类

作用是关闭各种资源(IO流和端口)

代码语言:javascript
复制
package cn.Himit_ZH.ServerTransponder;

import java.io.Closeable;


/**
 * 名字:工具类
 * 作用:关闭各种资源
 * @author Himit_ZH
 *
 */
public class CloseUtils {
    public static void close(Closeable... targets ) {
        for(Closeable target:targets) {
            try {
                if(target!=null) {
                    target.close();
                }
            }catch(Exception e) {
             System.out.println("资源关闭失败");
            }
        }
    }
}

演示

登陆界面 默认的管理员账号为admin1或者admin2 密码都为admin 用户账号昵称可以随便设置 密码为聊天室房间默认密码666 要修改的话在步骤②中的代码找,有备注了

群聊私聊

两个广告指令

踢人

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020年4月6日 2,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 具体用途
  • 步骤
    • ① 首先是实现登陆验证的服务器端
      • ②第二是识别管理员指令和转发用户内容的中转服务器
      • ③客户端
      • ④最后一个是三个运行程序都要用的工具类
      • 演示
      相关产品与服务
      访问管理
      访问管理(Cloud Access Management,CAM)可以帮助您安全、便捷地管理对腾讯云服务和资源的访问。您可以使用CAM创建子用户、用户组和角色,并通过策略控制其访问范围。CAM支持用户和角色SSO能力,您可以根据具体管理场景针对性设置企业内用户和腾讯云的互通能力。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档