当前位置:首页 > 开发教程 > java教程 >

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

时间:2022-05-20 09:30 来源:未知 作者:突然诚恳 收藏

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

本文实例为大家分享了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

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

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

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

jiji收到:

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

yaou收到:

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

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

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

jiji收到:

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

yaou没有收到:

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

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


下一篇:没有了

java教程阅读排行

最新文章