JAVA实现聊天室(局域网)

news/2024/11/17 5:21:15/

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( //建立监听的ServerSocketServerSocket 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> {//创建一个线程安全的HashMappublic 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查找keypublic synchronized k getKeyByValue(v value){//遍历所有key组成的集合for (k key:map.keySet()){//如果指定key对应的value与被搜索的value相同,则返回对应的keyif(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没有收到:
在这里插入图片描述


http://www.ppmy.cn/news/933705.html

相关文章

基础聊天室的实现,实现同局域网的聊天,有详细代码

** 聊天室的实现&#xff0c;基本步骤解析 ** 总体思想结构 1.建立服务器端&#xff0c;服务器端不需要界面 建立一个包为服务器包 serve 包内应该有服务器的主方法用来启动服务器&#xff0c;和一个用来接收客户端消息并且转发给所有的客户端的线程类 服务器给所有客户端发消…

web网络聊天室

花了四天时间做了一个简单的web聊天室 前端页面效果大概是下面这个样子 1.登陆界面 2.注册界面 这里首先会检查用户名是否重复&#xff0c; 如果重复&#xff0c;会提示你用户名已存在 反正显示可用 3.聊天室界面 登陆成功会在左边显示登陆人的名称以及当前在线人数。 然后…

局域网通信 | 基于广播实现简易聊天室

前言 事情是这个样子的&#xff0c;实验室的那个横向项目有一个需求&#xff1a;同一个 WIFI 下的设备之间可以实现实时的语音聊天。 于是这两天抽空闲时间捣鼓了一下局域网通信。现在基本实现语音通信了&#xff0c;是基于 UDP 广播实现的&#xff0c;但是不知道是 UDP 丢包…

局域网聊天工具

按企业部门进行划分用户组&#xff1b; 可实现单人、多人之间的文本对话&#xff1b; 方便高效的自动应答系统&#xff1b; 可在任何形式局域网及企业专线网中使用&#xff1b; 谈话窗口中可插入各种心情图标&#xff1b; 强大完备的企业电脑信息查询功能&#xff1b…

局域网实时聊天

本程序可以使用ip也可以使用主机名&#xff0c;这样就可以在打包之后&#xff0c;就不需要一直动态修改IP了 服务器端代码&#xff1a; public partial class FServer : Form{public FServer(){InitializeComponent();TextBox.CheckForIllegalCrossThreadCalls false;}Thread …

简单局域网聊天室--Java版

Java 的Socket编程&#xff1a; 1、TCP协议是面向连接的、可靠的、有序的、以字节流的方式发送数据&#xff0c;通过三次握手方式建立连接&#xff0c;形成传输数据的通道&#xff0c;在连接中进行大量数据的传输&#xff0c;效率会稍低 2、Java中基于TCP协议实现网络通信的类…

局域网聊天

实现局域网聊天&#xff0c;涉及到服务器端和用户端&#xff0c;使用MFC编程实现。 设计服务器端和用户端界面分别建立两个项目&#xff0c;ChatRoomSever和ChatRoomClientChatRoomSever用于创建Socket并监听和接受信息ChatRoomClient用于创建Socket并连接ChatRoomSever 具体…

超赞的8款开源聊天软件

qq曾经风靡一时&#xff0c;作为一名菜鸟&#xff0c;多想自己整一套聊天系统&#xff0c;在局域网内让大家使用。忙里偷闲&#xff0c;搜罗了一堆聊天系统&#xff0c;和我有一样兴趣的同学&#xff0c;可以运行下面的一两款聊天软件&#xff0c;也算是圆了曾经的梦吧&#xf…