类和接口

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怎么用局域网实现聊天室功能


本文参考链接:https://www.yisu.com/zixun/696779.html
评论关闭
IT虾米网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!

Java如何实现鲜花商城系统