当前位置:

首页 > 编程开发 > Java怎么用局域网实现聊天室功能

Java怎么用局域网实现聊天室功能

类和接口Server类(服务器端)packageTest;importjava.io.IOException;importjava.io.PrintStream;importjava.net.ServerSocket;importjava.net.Socket;publicclassServer{privatestaticfinalintSERVER_PORT=30000;//使用CrazyitMap对象来保存每个客户名字和对应输出流之间的对应关系publicstaticCrazyitMapclients

本文目录

    类和接口

    Java怎么用局域网实现聊天室功能

    Server类(服务器端)

    package Test;
    
    import java.io.IOException;
    import java.io.PrintStream;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    public class Server {
        private static final int SERVER_PORT=30000;
        //使用CrazyitMap对象来保存每个客户名字和对应输出流之间的对应关系
        public static CrazyitMap clients=new CrazyitMap<>();
        public void init(){
            try( //建立监听的ServerSocket
                 ServerSocket ss=new ServerSocket(SERVER_PORT))
            {
                //采用死循环来不断地接收来自客户端的请求
                while(true){
                    Socket socket=ss.accept();
                    new ServerThread(socket).start();
                }
            }
            //如果抛出异常
            catch (IOException ex){
                System.out.println("服务器启动失败,是否端口"+SERVER_PORT+"已被占用");
            }
        }
        public static void main(String[] args){
            Server server=new Server();
            server.init();
        }
    }

    ServerThread类

    package Test;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.PrintStream;
    import java.net.Socket;
    
    public class ServerThread extends Thread {
        private Socket socket;
        BufferedReader br = null;
        PrintStream ps = null;
    
        //定义一个构造器,用于接收一个Socket来创建ServerThread线程
        public ServerThread(Socket socket) {
            this.socket = socket;
        }
    
        public void run() {
            try {
                //获取该Socket对应的输入流
                br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                //获取该Socket对应的输出流
                ps = new PrintStream(socket.getOutputStream());
                String line = null;
                while ((line = br.readLine()) != null) {
                    //如果读到的行以CrazyitProtocol.USER_ROUND开始,并以其结束
                    //则可以确定读到的是用户登录的用户名
                    if (line.startsWith(CrazyitProtocol.USER_ROUND) && line.endsWith(CrazyitProtocol.USER_ROUND)) {
                        //得到真实消息
                        String userName = getRealMsg(line);
                        //如果用户名重复
                        if (Server.clients.map.containsKey(userName)) {
                            System.out.println("重复");
                            ps.println(CrazyitProtocol.NAME_REP);
                        } else {
                            System.out.println("成功");
                            ps.println(CrazyitProtocol.LOGIN_SUCCESS);
                            Server.clients.put(userName, ps);
                        }
                    }
                    //如果读到的行以CrazyitProtocol.PRIVATE_ROUND开始,
                    //则可以确定是私聊信息,私聊信息只向特定的输入流发送
                    else if (line.startsWith(CrazyitProtocol.PRIVATE_ROUND) && line.endsWith(CrazyitProtocol.PRIVATE_ROUND)) {
                        //得到真实的消息
                        String userAndMsg = getRealMsg(line);
                        //以SPLIT_SIGN分割字符串,前半是私聊用户,后半是聊天信息
                        String user = userAndMsg.split(CrazyitProtocol.SPLIT_SIGN)[0];
                        String msg = userAndMsg.split(CrazyitProtocol.SPLIT_SIGN)[1];
                        //获取私聊用户对应的输出流,并发送私聊信息
                        Server.clients.map.get(user).println(Server.clients.getKeyByValue(ps) + "悄悄对你说:" + msg);
                    }
                    //公聊要向每一个Socket发送
                    else {
                        //得到真实消息
                        String msg = getRealMsg(line);
                        //遍历clients中的每个输出流
                        for (PrintStream clientPs : Server.clients.valueSet()) {
                            clientPs.println(Server.clients.getKeyByValue(ps) + "说:" + msg);
                        }
                    }
                }
            }
            //捕获到异常后,表明Socket对应的客户端已经出现了问题
            //所以程序将其对应的输出流从Map中删除
            catch (IOException e) {
                Server.clients.removeByValue(ps);
                System.out.println(Server.clients.map.size());
                //关闭网络,IO资源
                try {
                    if (br != null) {
                        br.close();
                    }
                    if (ps != null) {
                        ps.close();
                    }
                    if (socket != null) {
                        socket.close();
                    }
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
        }
    
        //将读到的内容去掉前后协议字符,恢复成真实数据
        private String getRealMsg(String line) {
            return line.substring(CrazyitProtocol.PROTOCOL_LEN,line.length()-CrazyitProtocol.PROTOCOL_LEN);
        }
    }

    Client类

    package Test;
    
    import javax.swing.*;
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.PrintStream;
    import java.net.Socket;
    import java.net.UnknownHostException;
    
    public class Client {
        private static final int SERVER_PORT=30000;
        private Socket socket;
        private PrintStream ps;
        private BufferedReader brServer;
        private BufferedReader keyIn;
        public void init(){
            try
            {
                //初始化代表键盘的输入流
                keyIn=new BufferedReader(new InputStreamReader(System.in));
                //连接到服务器端
                socket=new Socket("127.0.0.1",SERVER_PORT);
                //获取该Socket对应的输入流和输出流
                ps=new PrintStream(socket.getOutputStream());
                brServer=new BufferedReader(new InputStreamReader(socket.getInputStream()));
                String tip=" ";
                //采用不断循环地弹出对话框要求输入用户名
                while(true){
                    String userName= JOptionPane.showInputDialog(tip+"输入用户名");
                    //用户输入的用户名前后增加协议字符串后发送
                    ps.println(CrazyitProtocol.USER_ROUND+userName+CrazyitProtocol.USER_ROUND);
                    //读取服务器端的响应
                    String result=brServer.readLine();
                    //如果用户名重复,则开始下一次循环
                    if (result.equals(CrazyitProtocol.NAME_REP)){
                        tip="用户名重复,请重试";
                        continue;
                    }
                    //服务器端登录成功
                    if (result.equals(CrazyitProtocol.LOGIN_SUCCESS)){
                        break;
                    }
                }
            }
            //捕获到异常,关闭网络资源,并退出该程序
            catch (UnknownHostException ex){
                System.out.println("找不到远程服务器,请确定服务器已经启动");
                closeRs();
                System.exit(1);
            }
            catch(IOException ex){
                System.out.println("网络异常,请重新登录");
                closeRs();
                System.exit(1);
            }
            //以该Socket对应的输入流启动ClientThread线程
            new ClientThread(brServer).start();
        }
        //定义一个读取键盘输出,并以网络发送的方法
        private void readAndSend(){
            try
            {
                //不断读取键盘输入
                String line=null;
                while ((line=keyIn.readLine())!=null){
                    //如果发送的信号中有冒号,并以//开头,则认为想发送私聊信息
                    if (line.indexOf(":")>0&&line.startsWith("//")){
                        line=line.substring(2);
                        ps.println(CrazyitProtocol.PRIVATE_ROUND+line.split(":")[0]+CrazyitProtocol.SPLIT_SIGN+line.split(":")[1]+CrazyitProtocol.PRIVATE_ROUND);
                    }
                    else{
                        ps.println(CrazyitProtocol.MSG_ROUND+line+CrazyitProtocol.MSG_ROUND);
                    }
                }
            }
            catch (IOException ex){
                System.out.println("网络通信异常!请重新登录");
                closeRs();
                System.exit(1);
            }
        }
        //关闭Socket,输入流,输出流的方法
        private void closeRs(){
            try
            {
                if (keyIn!=null){
                    ps.close();
                }
                if (brServer!=null){
                    ps.close();
                }
                if (ps!=null){
                    ps.close();
                }
                if (socket!=null){
                    keyIn.close();
                }
            }
            catch (IOException ex){
                ex.printStackTrace();
            }
        }
    
        public static void main(String[] args){
            Client client=new Client();
            client.init();
            client.readAndSend();
        }
    }

    ClientThread类

    package Test;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    
    public class ClientThread extends Thread {
        //该客户端线程负责处理输入流
        BufferedReader br=null;
        //使用一个网络输入流来创建客户端线程
        public ClientThread(BufferedReader br){
            this.br=br;
        }
        public void run(){
            try
            {
                String line=null;
                //不断地从输入流中读取数据,并将这些数据打印输出
                while((line=br.readLine())!=null){
                    System.out.println(line);
                }
            }
            catch (IOException ex){
                ex.printStackTrace();
            }
            finally {
                try {
                    if (br!=null){
                        br.close();
                    }
                }
                catch (IOException ex){
                    ex.printStackTrace();
                }
            }
        }
    }

    CrazyitMap类

    package Test;
    
    import java.util.*;
    
    public class CrazyitMap {
        //创建一个线程安全的HashMap
        public Map map= Collections.synchronizedMap(new HashMap());
        //根据value来删除指定项
        public synchronized void removeByValue(Object value){
            for (Object key:map.keySet()){
                if (map.get(key)==value){
                    map.remove(key);
                    break;
                }
            }
        }
        //获取所有value组成的Set集合
        public synchronized Set valueSet(){
            Set result=new HashSet();
            //将map中的所有value添加到result集合中
            map.forEach((key,value)->result.add(value));
            return result;
        }
        //根据value查找key
        public synchronized k getKeyByValue(v value){
            //遍历所有key组成的集合
            for (k key:map.keySet()){
                //如果指定key对应的value与被搜索的value相同,则返回对应的key
                if(map.get(key)==value||map.get(key).equals(value)){
                    return key;
                }
            }
            return null;
        }
        //实现put()方法,该方法不允许value重复
        public synchronized v put(k key,v value){
            //遍历所有value组成的集合
            for (v val:valueSet()){
                //如果某个value与试图放入集合的value相同
                //则抛出一个RuntimeException异常
                if (val.equals(value)&&val.hashCode()==value.hashCode()){
                    throw new RuntimeException("MyMap实例不允许有重复的value");
                }
            }
            return map.put(key,value);
        }
    }

    CrazyitProtocol类

    package Test;
    
    public interface CrazyitProtocol {
        //定义协议字符串的长度
        int PROTOCOL_LEN=2;
        //下面是一些协议字符串,服务器端和客户端交换的信息都应该在前后添加这种特殊字符串
        String MSG_ROUND="ηθ";
        String USER_ROUND="∏∑";
        String LOGIN_SUCCESS="1";
        String NAME_REP="-1";
        String PRIVATE_ROUND="★【";
        String SPLIT_SIGN="卐";
    }

    运行结果:

    打开服务器并且运行三个客户端用户名分别是xuwei,jiji和yaou

    Java怎么用局域网实现聊天室功能

    首先发送一句公开信息:
    xuwei发送了一句话

    Java怎么用局域网实现聊天室功能

    jiji收到:

    Java怎么用局域网实现聊天室功能

    yaou收到:

    Java怎么用局域网实现聊天室功能

    再发送一句私聊信息给jiji
    xuwei发送了一句悄悄话:

    Java怎么用局域网实现聊天室功能

    jiji收到:

    Java怎么用局域网实现聊天室功能

    yaou没有收到:

    Java怎么用局域网实现聊天室功能

    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发 Java
    相关文章 更多
    Java单元测试入门:使用JUnit 5编写第一个测试用例
    Java单元测试入门:使用JUnit 5编写第一个测试用例

    面向初学者的JUnit 5实用入门指南。从测试概念、Maven依赖配置,到手把手编写首个单元测试用例及断言验证,助你掌握Java单元测试的核心流程。

    Java变量未初始化报错解析:局部变量与成员变量默认值差异
    Java变量未初始化报错解析:局部变量与成员变量默认值差异

    深入解析Java中局部变量未初始化编译报错与成员变量自动赋予默认值的机制差异,涵盖JVM内存分配、编译期确定性赋值检查与实际排查修复方案。

    Java获取当前时间并格式化输出:DateTimeFormatter与SimpleDateFormat
    Java获取当前时间并格式化输出:DateTimeFormatter与SimpleDateFormat

    详细讲解在Java中获取当前系统时间并进行格式化输出的两种核心方案:基于Java 8全新日期时间API的DateTimeFormatter与传统遗留的SimpleDateFormat,包含完整代码示例、线程安全机制对比及生产选型建议。

    Java中final与static final常量的定义及初始化规则
    Java中final与static final常量的定义及初始化规则

    深入解析Java中final变量与static final常量的定义、内存语义、初始化时机及合法赋值路径,涵盖编译期常量优化与实战避坑指南。

    Java抽象方法与接口方法的区别及选型建议
    Java抽象方法与接口方法的区别及选型建议

    深入对比Java中抽象类抽象方法与接口方法的语法演进、设计意图及运行期差异,并提供清晰的架构选型决策流程与实战范例。

    Java实现HTTP请求与JSON解析的完整代码示例
    Java实现HTTP请求与JSON解析的完整代码示例

    本文提供Java标准库HttpClient发起HTTP GET/POST请求并结合Jackson进行JSON数据反序列化与序列化的完整代码示例与工程实践指南。

    Java递归出现StackOverflowError的原因分析及栈空间优化方案
    Java递归出现StackOverflowError的原因分析及栈空间优化方案

    详细分析Java递归调用出现StackOverflowError的原因,结合代码说明线程栈、栈帧和递归深度之间的关系,并介绍终止条件排查、迭代改写、减少栈帧开销以及通过-Xss调整JVM栈空间的方法。

    Java空指针异常(NPE)的代码排查与修复实例
    Java空指针异常(NPE)的代码排查与修复实例

    针对Java中常见的NullPointerException(NPE),本文从堆栈日志定位、典型代码触发场景、具体修复代码对比到防御体系进行系统讲解,提供实用且易上手的排查与修复方案。

    selenium上传文件教程本地文件路径设置方法
    selenium上传文件教程本地文件路径设置方法

    深入解析Selenium处理文件上传的技术细节,涵盖标准HTML控件的路径直接注入法与非标准控件的系统级模拟方案,提供Windows与Linux环境下的路径设置最佳实践及常见异常排查。

    大数据开发语言选型:Java对比Scala与Python的优缺点及适用场景
    大数据开发语言选型:Java对比Scala与Python的优缺点及适用场景

    针对大数据工程场景,系统对比Java、Scala与Python在执行性能、生态结合、开发效率和维护成本上的核心差异,给出清晰的架构选型依据与落地方案。

    查看更多
    精品专题 更多
    装机必备
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows
    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程
    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    Mac软件 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    Aperty macOS版
    Aperty macOS版
    macOS

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    WINDOWS 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    PixTV 网页版
    PixTV 网页版
    Windows

    PixTV 是一款在浏览器中使用的 AI 视觉内容创作平台,提供图片、视频、音频、文字生成、AI 分镜、局部重绘、提示词反推和无限画布等工具,适合短剧、漫剧、广告及社交媒体内容制作。