java基于socket实现聊天群聊敏感词汇过滤功能(代码片段)

吹灭读书灯一身都是月 吹灭读书灯一身都是月     2022-12-10     147

关键词:

首先的话,这个代码主要是我很久以前写的,然后当时还有很多地方没有理解,现在再来看看这份代码,实在是觉得丑陋不堪,想改,但是是真的改都不好改了…
所以,写代码,规范真的很重要。

实现的功能:

  1. 用户私聊
  2. 群聊功能:进群退群,群发消息,查看群聊
  3. 查看自己的消息记录
  4. 通过文件流,设置敏感词汇过滤(这里还用到了字典树…)不过我还有点不熟练…
  5. 离线,退出登录

不足:
emmm,其实说到不足的地方实在是太多了。
首先功能并没有完全完善,尤其是群聊的功能(但是我觉得后面的功能实现了也意义不大了)
然后,写代码并不规范。
也没有用到Java面向对象的知识,只存放用户的昵称,没有设置密码什么的
还要设置个,当用户上线之后,再来发送缓存之中的数据。
数据没有保存起来,关闭程序之后,数据消失了…
最开始的时候,我还不怎么会使用集合,后面发现在集合中放List(其实就是对象嘛),可以存很多东西的…
总而言之就是,还是要多写代码的,同时要多学习知识啊!!!

开始上代码!

目录结构


我这里的话,把我这四个类都放在test1包下。

实在是,这里用到了很多if else…然后,我这里想调用对应的方法语句都是要先输入对应的中文前缀的,很麻烦…建议大家使用循环,然后每次提示用户输入对应的指令。

TCPServer

首先就是要先启动服务端,如果没有启动的话是会报错的!!!

package test1;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TCPServer 

    public static void main(String[] args) 
        TCPServer server = new TCPServer();
        server.start();
    

    /**
     * 创建线程池来管理客户端的连接线程
     * 避免系统资源过度浪费
     */
    private ServerSocket serverSocket;
    private ExecutorService exec;
    /**
     * 存放用户昵称,打印流
     */
    private Map<String, PrintWriter> storeInfo;
    /**
     * 存放客户端之间私聊的信息
     */
    private Map<String, LinkedList<String>> storeMessages;
    /**
     * 用户没有上线的消息【我这里没有实现】
     */
    private Map<String, String> waitMessages;

    /**
     * 群 K:群名称,Value:人员的昵称集合
     */
    Map<String, LinkedList<String>> aGroup = new LinkedHashMap<>();

    public TCPServer() //构造器
        try 
            serverSocket = new ServerSocket(9999);
            storeInfo = new ConcurrentHashMap<String, PrintWriter>();
            exec = Executors.newCachedThreadPool();//创建线程池
            storeMessages = new ConcurrentHashMap<String, LinkedList<String>>();
         catch (IOException e) 
            e.printStackTrace();
        
    

    public void start() 
        try 
            while (true) 
                System.out.println("服务端等待客户端连接... ... ");
                Socket socket = serverSocket.accept();//出现一个客户才会accept()
                System.out.println("客户端:“" + socket.getInetAddress().getHostAddress() + "”连接成功! ");
                //启动一个线程,由线程来处理客户端的请求,这样可以再次监听下一个客户端的连接
                //每次都是一个服务端Socket跟一个客户端绑定。同时服务端开启监听客户端的请求输入流
                exec.execute(new ListenerClient(socket)); //通过线程池来分配线程      监听客户机    出现一个客户,就新建一个线程
            
         catch (Exception e) 
            e.printStackTrace();
        
    

    /**
     * 创建内部类来获取昵称
     * 监听客户端
     * 该线程体用来处理给定的某一个客户端的消息,循环接收客户端发送 的每一个字符串,并输出到控制台
     */
    class ListenerClient implements Runnable 
        private Socket socket;
        private String name;

        public ListenerClient(Socket socket) 
            this.socket = socket;
        

        /**
         * 管理昵称的方法
         */
        private String getName() throws Exception 
            //服务端的输入流读取客户端发送来的昵称输出流
            BufferedReader bReader = new BufferedReader(
                    new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8));
            //服务端将昵称验证结果通过自身的输出流发送给客户端
            PrintWriter ipw = new PrintWriter(
                    new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8), true);
            //读取客户端发来的昵称
            while (true) 
                String nameString = bReader.readLine();
                if ((nameString.trim().length() == 0) || storeInfo.containsKey(nameString)) 
                    ipw.println("FAIL");//发送给客户端
                 else 
                    ipw.println("OK");
                    return nameString;
                
            
        

        /**
         * 监听方法
         * 通过客户端的Socket获取客户端的输出流,用来将消息发送给客户端
         */
        @Override
        public void run() 
            try 
                PrintWriter pw = new PrintWriter(
                        new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8), true);
                name = getName();
                putIn(name, pw, storeInfo);//将客户昵称和服务端所说的内容存入共享集合HashMap-storeInfo中
                Thread.sleep(100);
                // 服务端通知所有客户端,某用户上线(是群发的)
                sendToAll("[系统通知] “" + name + "”已上线");
                System.out.println("[系统通知] “" + name + "”已上线");
                /* 读取客户端
                 * 通过客户端的Socket获取输入流读取客户端发送来的信息
                 */
                BufferedReader bReader = new BufferedReader(
                        new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8));

                String msgString = null;//用msgString来获取客户端的输入
                while ((msgString = bReader.readLine()) != null) 
                    LinkedList<String> msgList = storeMessages.get(name);
                    if (msgList == null) 
                        msgList = new LinkedList<String>();
                    
                    // 检验是否为私聊(格式:@昵称:内容)
                    if (msgString.startsWith("@")) 
                        int index = msgString.indexOf(":");//@deng:xxx(冒号后面为内容)
                        if (index == -1) 
                            index = msgString.indexOf(":");
                        
                        if (index >= 0) 
                            String theName = msgString.substring(1, index);//获取昵称
                            String info = msgString.substring(index + 1);//获取发送的内容
                            if (isBlank(info)) 
                                pw.println("[系统提示]:给好友发送的消息不能为空哦!");
                            
                            info = "“" + name + "”:" + info;
                            //将私聊信息发送出去
                            boolean b = sendToSomeone(theName, isIllegal(info));
                            if (!b) 
//返回给原来的用户:消息发送失败,找不到人
                                pw.println("[系统提示]:未找到指定用户“" + theName + "“,消息发送失败");
                            
                            msgList.add(msgString);
                            storeMessages.put(name, msgList);
                            continue;
                        
                     else if (msgString.startsWith("新建群:") || msgString.startsWith("新建群:")) 
                        creatGroup(msgString, name);
                        continue;
                     else if (msgString.contains("群邀请:") || msgString.contains("群邀请:")) 
                        groupInvite(msgString, name);
                        continue;
                     else if (msgString.startsWith("退群:") || msgString.startsWith("退群:")) 
                        String groupName = msgString.substring(3);
                        exitGroup(groupName, name);
                        continue;
                     else if (msgString.startsWith("我想进群:") || msgString.startsWith("我想进群:") ) 
                        String groupName = msgString.substring(5);
                        acceptGroup(groupName, name);
                        continue;
                     else if (msgString.contains("查看我加入的群聊")) 
                        pw.println("我加入的群聊有"+showMyGroups(name));
                        continue;
                     else if ("查看消息记录".equals(msgString)) 
                        printOnlineUser(name);
                        printAllMessages(name);
                        continue;
                     else if ("撤回最近一条消息".equals(msgString)) 
                        withdraw(name);
                        continue;
                     else if (msgString.startsWith("群发给")) //在群里发信息:群发给XXX:。。。1.判断是否在群XXX里   2.群发内容
                        int index = msgString.indexOf(':');
                        if (index == -1) 
                            index = msgString.indexOf(":");
                        
                        String theGroupName = msgString.substring(3, index);//群聊名称
                        String theMsg = msgString.substring(index + 1);//内容
                        sendToGroup(theGroupName, isIllegal(theMsg), name);
                        continue;
                    
                    if ("exit".equals(msgString)) //手动退出程序
                        remove(name);
                        sendToAll("[系统通知] “" + name + "”已经手动下线了。");// 通知所有客户端,某某客户已经下线
                    
                    //否则:(自己乱发消息) 遍历所有输出流,将该客户端发送的信息转发给所有客户端
                    System.out.println(name + ":" + isIllegal(msgString));
                    sendToSomeone(name, isIllegal(msgString));

                    msgList.add(msgString);
                    storeMessages.put(name, msgList);
                
             catch (Exception e) 
                // e.printStackTrace();
             finally 
                remove(name);
                sendToAll("[系统通知] “" + name + "”已经下线了。");// 通知所有客户端,某某客户已经下线
                if (socket != null) 
                    try 
                        socket.close();
                     catch (IOException e) 
                        e.printStackTrace();
                    
                
            
        
    

    private boolean isBlank(String msg) 
        return msg == null || "".equals(msg.trim());
    

    private void putIn(String name, PrintWriter value, Map<String, PrintWriter> store) 
        synchronized (this) 
            store.put(name, value);
        
    

    /**
     * 将给定的输出流从共享集合中删除
     */
    private synchronized void remove(String key) 
        storeInfo.remove(key);
        System.out.println("系统当前在线人数为:" + storeInfo.size());
    

    /**
     * 将给定的消息转发给所有客户端(群发)
     */
    private synchronized void sendToAll(String message) 
        for (PrintWriter everyone : storeInfo.values()) 
            everyone.println(message);
        
    

    /**
     * 群发信息
     *
     * @param groupName 群聊名称
     * @param message   群发的内容
     * @param username  发信息的人
     */
    private synchronized void sendToGroup(String groupName, String message, String username) 
        LinkedList<String> nickNameList = aGroup.get(groupName);
        if (nickNameList == null) 
            sendToSomeone(username, "未找到指定的群:" + groupName);
         else 
            for (String name : nickNameList) 
                sendToSomeone(name, "【"+groupName + "】群的“" + username + "”说" + message);
            
        
    


    /**
     * 将给定的消息转发给私聊的客户端
     */
    private synchronized boolean sendToSomeone(String name, String message) //每一个名字对应一个只给它发送信息的PrintWriter
        PrintWriter pw = storeInfo.get(name); //将对应客户端的聊天信息取出作为私聊内容发送出去(相当于只发给指定的name的)
        if (pw != null) 
            pw.println(message);
            return true;
        
        return false;
    

    private static final SensitiveFilter sensitiveFilter = new SensitiveFilter();

    /**
     * 检测从服务端读入的信息是否合法-->读取 不含敏感信息
     * 否侧把敏感词汇进行过滤
     */
    private synchronized String isIllegal(String message) 
        String msg = sensitiveFilter.filter(message);
        if (msg == null) 
            return "[系统提示]:消息为空,发送失败了";
        
        return msg;
    


    private synchronized void creatGroup(String msgString, String hostname) 
        String groupName = msgString.substring(4);
        //1.建立Map,添加群主及群聊名称
        LinkedList<String> nickNameList = new LinkedList<>();
        nickNameList.add(hostname);
        aGroup.put(groupName

基于java实现hello/hi简单网络聊天程序

目录Socket简要阐述Socket的概念Socket原理hello/hi的简单网络聊天程序实现服务器端客户端程序执行结果跟踪分析调用栈&LinuxAPI对比创建ServerSocket调用栈图示源码分析Socket绑定调用栈图示源码分析Socket监听调用栈图示源码分析Socket... 查看详情

java编程实例-tcp聊天室代码实现(代码片段)

Tcp多人聊天室实现客户端:功能:数据发送数据接收技术:socket输入流和输出流多线程,客户端功能模块有两个线程聊天方式:群聊私聊私聊方法:@服务器用户id号:msg服务器:功能:数据转发用户注册技术:ServerSocket每一个用户对应的Sock... 查看详情

过滤器与拦截器

...器关注的是方法调用,比如拦截敏感词汇。1,拦截器是基于java反射机制来实现的,而过滤器是基于函数回调来实现的。(有人说,拦截器是基于动态代理来实现的)2,拦截器不依赖servlet容器,过滤器依赖于servlet容器。3,拦截... 查看详情

敏感词汇过滤(不区分大小写)

最近项目中,用户评论内容需要屏蔽敏感词汇,从网上总结以下方法,(不区分大小写,如想设置大小写敏感,可以把代码中content..toLowerCase()去掉).具体看代码:1.读取敏感词汇文档<spanstyle="font-size:18px;">packagecom.blemall.wizlife.uti... 查看详情

socket.io实现在线群聊

我自己在用socket.io开发,对官方网站上的文档,进行简单的整理,然后自己写了一个简单的聊天程序。最最开始先安装socket.io:1npminstallsocket.io利用Node的搭建Http服务分为两个文件,服务端文件app.js和客户端index.htmlapp.js01varapp=requir... 查看详情

javaweb中的filter过滤敏感词汇案例

需求:对含有bad.txt中的敏感词汇的句子进行替换,替换成星号bad.txt放在src目录下笨蛋坏蛋FilterDemoimportjavax.servlet.*;importjavax.servlet.annotation.WebFilter;importjava.io.BufferedReader;importjava.io.FileNotFoundException;importjava. 查看详情

过滤器与拦截器的区别

...器关注的是方法调用,比如拦截敏感词汇。4.1,拦截器是基于java反射机制来实现的,而过滤器是基于函数回调来实现的。(有人说,拦截器是基于动态代理来实现的)4.2,拦截器不依赖servlet容器,过滤器依赖于servlet容器。4.3,... 查看详情

strtr对用户输入的敏感词汇进行过滤

/***过滤用户输入的基本数据,防止script攻击**@accesspublic*@returnstring*/functioncompile_str($str){$arr=array(‘<‘=>‘<‘,‘>‘=>‘>‘,‘"‘=>‘”‘,"‘"=>‘’‘);returnstrtr($str,$arr);}  查看详情

前端实现敏感字过滤

在开发聊天或者留言之类的功能的时候,通常需要过滤敏感词,下面总结了两种方法。1、迭代敏感字数组,拼接过滤敏感字正则,然后利用 replace 把匹配到的敏感字替换为*dom结构如下:<textarearows="5"cols="50"id="txt1">你... 查看详情

linuxc基于socket实现聊天室的登陆注册怎么实现

参考技术A可以使用数据库,也可以写入文件,最好写入xml文件吧 参考技术B原创一份什么时候交呢. 查看详情

网站是怎么屏蔽脏话的呢:简单学会springboot项目敏感词违规词过滤方案(代码片段)

...而这两者都少不了对于敏感词进行过滤的自动维护措施。基于这样的措施,我们才能基本保证用户在使用社区的过程中,不至于被敏感违规词汇包围,才能够正常的进行发布帖子和评论,享受美好的社区氛围。目... 查看详情

基于java版聊天室的设计

本聊天系统利用Java中的socket网络编程和多线程技术实现。主要包括登陆连接、服务器管理、客户聊天三大功能。管理员和用户经过登陆界面分别进入到服务器端和客户端,客户通过socket连接服务器,服务器通过多线程技... 查看详情

基于java的socket简单聊天编程

socket编程:一:什么是socket:socket是BSDUNIX的通信机制,通常称为“套接字”,其英文原意是“孔”或“插座”。有些顾名思义,socket正如其英文原意一样,像是一个多孔插座,可以提供多个端口的连接服务。... 查看详情

java网络编程基础—基于tcp的nio简单聊天系统

在Java网络编程基础(四)中提到了基于Socket的TCP/IP简单聊天系统实现了一个多客户端之间护法消息的简单聊天系统。其服务端采用了多线程来处理多个客户端的消息发送,并转发给目的用户。但是由于它是基于Socket的,因此是... 查看详情

socket聊天程序——初始设计

...sdn上看到2个一样问答(问题A,问题B),那就是编写一个基于socket的聊天程序,正好最近刚用socket做了一些事,出于兴趣,自己抽了几个晚上的空闲时间敲了一个,目前仅支持单聊,群聊,文件传送这些功能。首先,贴出一个丑... 查看详情

转:java实现敏感词过滤

 敏感词、文字过滤是一个网站必不可少的功能,如何设计一个好的、高效的过滤算法是非常有必要的。前段时间我一个朋友(马上毕业,接触编程不久)要我帮他看一个文字过滤的东西,它说检索效率非常慢。我把它程序拿... 查看详情

servlet过滤器

...Jsp,Servlet,静态图片文件或静态html文件等进行拦截,从而实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。  ServletAPI中提供了一个Filter接口,开发web应用时,如果编写的Java... 查看详情

基于flask写的web_socket单聊和群聊(代码片段)

群聊 fromflaskimportFlask,request,render_templatefromgeventwebsocket.handlerimportWebSocketHandlerfromgevent.pywsgiimportWSGIServerfromgeventwebsocket.websocketimportWebSocketapp=Flask(__name__)use 查看详情