我的编程空间,编程开发者的网络收藏夹
学习永远不晚

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

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

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

本文实例为大家分享了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<String,PrintStream> 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<k,v> {
    //创建一个线程安全的HashMap
    public Map<k,v> map= Collections.synchronizedMap(new HashMap<k,v>());
    //根据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<v> valueSet(){
        Set<v> result=new HashSet<v>();
        //将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

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

jiji收到:

yaou收到:

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

jiji收到:

yaou没有收到:

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程网。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

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

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

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

这篇文章主要介绍了Java怎么用局域网实现聊天室功能的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Java怎么用局域网实现聊天室功能文章都会有所收获,下面我们一起来看看吧。类和接口Server类(服务器端)pa
2023-06-30

Java聊天室之实现聊天室服务端功能

这篇文章主要为大家详细介绍了Java简易聊天室之实现聊天室服务端功能,文中的示例代码讲解详细,具有一定的借鉴价值,需要的可以了解一下
2022-11-13

Java聊天室之实现聊天室客户端功能

这篇文章主要为大家详细介绍了Java简易聊天室之实现聊天室客户端功能,文中的示例代码讲解详细,具有一定的借鉴价值,需要的可以了解一下
2022-11-13

Java NIO怎么实现聊天室功能

这篇文章主要介绍了Java NIO怎么实现聊天室功能,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。具体内容如下代码里面已经包含了必要的注释,这里不详述了。实现了基本的聊天室功
2023-06-21

使用socket实现网络聊天室和私聊功能

使用socket技术实现网络聊天室和私聊功能,具体内容如下话不多说先上图:1、聊天室群聊页面在线用户的联系人列表socket连接页面私聊页面项目介绍与服务端实现socket连接:每个客户端连接到服务器的时候,服务器会将每个连接的socket
2023-05-30

android socket聊天室功能实现

前提概要 笔者很久之前其实就已经学习过了socket,当然也是用socket做过了聊天室,但是觉得此知识点比较一般,并无特别难的技术点,于是也并未深究。 然而近期一个项目中对socket的使用却让笔者感觉socket强大无比,可以实现诸多
2022-06-06

JavaScript实现QQ聊天室功能

这篇文章主要为大家详细介绍了JavaScript实现QQ聊天室功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
2022-11-13

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录