Java实现局域网聊天室功能(私聊、群聊)

网友投稿 265 2022-07-29


本文实例为大家分享了java实现局域网聊天室功能的具体代码,供大家参考,具体内容如下

Server 服务端

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=8080;

//使用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 服务端线程

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(userName+"上线");

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 客户端

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=8080;

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 客户端线程

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 容器

import java.util.*;

/**

* map容器

*

* @param

* @param

*/

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 接口

/**

* 自定义接口

*/

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="卐";

}

测试

1、启动服务端

2、启动客户端 (上线)

3 、群发

4、私聊 (//名字:)


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:java实现下载文件到默认浏览器路径(浏览器默认下载路径怎么设置)
下一篇:Java @Scheduled定时器用法解析
相关文章

 发表评论

暂时没有评论,来抢沙发吧~