使用Socket实现简单的私聊功能

服务端

package chatTest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
public class Server2 {
    public ServerSocket server;
    //私聊用map,key为昵称,value是对应消息,广播则遍历value
    private Map<String,PrintWriter> pri_map;
    // 初始化服务端
    public Server2() throws Exception {
        // 初始化的同时申请端口号
        server = new ServerSocket(8798);
        //初始化用于保存客户端输出流的Map集合
        pri_map = new HashMap<String,PrintWriter>();
    }
    //将客户端发送过来的信息以键值对形式存入map集合,(昵称,对应输出流)
    private void putIn(String key,PrintWriter value){
        pri_map.put(key,value);
    }
    //将给定的消息发送给私聊的客户端
    private synchronized void  sendMessageToOne(String name,String message) {
        //将对应客户端的聊天信息取出作为私聊内容发送出
        PrintWriter pw=pri_map.get(name);   //此处name为键,get(name)获取其值,即目标客户端的输出流(写)
        if (pw!=null){
            pw.println(message);        //如果目标输出流对象存在,将信息写入该流
        }
    }
    //将指定的输出流从共享集合map中删除
    private synchronized void remove(String key) {
        pri_map.remove(key);
    }
    //服务端开始工作的方法
    public void start(){
        try {
            while(true) {
                System.out.println("等待客户端连接...");
                //侦听并接受想连接到此套接字的客户端连接
                Socket socket = server.accept();
                //获取客户端ip地址
                InetAddress address = socket.getInetAddress();
                System.out.println("客户端:" + address.getHostAddress() + "连接成功! ");
                //创建一个实现Runnale接口的线程处理与客户端的交互
                ClientHandler handler= new ClientHandler(socket);
                Thread t = new Thread(handler);
                //启动线程
                t.start();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    //ClientHandler:处理与客户端的交互
    class ClientHandler implements Runnable{
        //该线程处理的客户端的Socket
        private Socket socket;
        // 客户端的地址信息,区分不同客户端(ip地址)
        private String host;
        //当前客户端用户昵称
        private String nickName;
        //消息接收者昵称
        private String targetName;
        //构造方法
        public ClientHandler(Socket socket) {
            this.socket = socket;
        }
        //线程的run()方法
        public void run() {
            try {
                //服务端的输入流br读取客户端发送的消息
                InputStream in = socket.getInputStream();
                InputStreamReader isr = new InputStreamReader(in,"UTF-8");
                BufferedReader br = new BufferedReader(isr);
                //通过Socket创建输出流pw用于将消息发送给客户端
                OutputStream out = socket.getOutputStream();
                OutputStreamWriter osw = new OutputStreamWriter(out,"UTF-8");
                PrintWriter pw = new PrintWriter(osw,true);
                //首先读取一行字符串为昵称
                nickName =  br.readLine();
                //将当前客户端昵称和其所说的内容存入共享集合HashMap中
                putIn(nickName,pw);
                //读取消息接收者客户端的昵称
                targetName = br.readLine();
                System.out.println(nickName+"的消息接收者:"+targetName);
                //将当前客户端输入的消息发送给消息接收者
                String message = null;
                while((message = br.readLine()) != null) {
                    message=nickName+":"+message;//发送的消息格式: 发送者昵称:消息
                    sendMessageToOne(targetName, message);
                }
            } catch (Exception e) {
            }finally {
                //处理当前客户端断开后的逻辑
                //将该客户端的输出流pw从共享集合中删除
                remove(nickName);
                sendMessageToOne(targetName,nickName+"下线了!");
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    public static void main(String[] args) {
        try {
            Server2 server2 = new Server2();
            server2.start();     //执行服务端start方法
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("服务端建立联系失败!");
        }
    }
}

客户端

package chatTest;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;

public class Client2 {
    private Socket socket;

    public Client2() throws Exception {
        //创建一个套接字并将其连接到指定主机上的指定端口号
        socket = new Socket("localhost",8798);
    }

    //客户端开始工作的方法
    public void start() {
        try {
            //创建Scanner类,用于获取用户输入
            Scanner scanner = new Scanner(System.in);

            //用户输入昵称
            String nickName = null;
            while(true) {
                System.out.println("请输入昵称:");
                nickName = scanner.nextLine();
                if(nickName.length()>0) {
                    break;
                }
                System.out.println("输入有误");
            }

            //输入消息接收者昵称
            String targetName = null;
            while(true) {
                System.out.println("请输入消息接收者昵称");
                targetName = scanner.nextLine();
                if(targetName.length()>0) {
                    break;
                }
                System.out.println("输入有误");
            }

            System.out.println("开始聊天吧!!!");

            //输出流(发送内容到服务端)
            OutputStream out = socket.getOutputStream();
            OutputStreamWriter osw = new OutputStreamWriter(out,"UTF-8");
            //第二参数为true会行刷新,
            PrintWriter pw =  new  PrintWriter(osw,true);

            //先将昵称和接受者发给服务器
            pw.println(nickName);
            pw.println(targetName);

            //启动"读取服务端发送过来的消息"的线程
            ServerHandler  handler = new ServerHandler();
            Thread t = new Thread(handler);
            t.start();

            //发送信息到服务端处理
            while(true) {
                pw.println(scanner.nextLine());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //该线程用来读取通过服务器端发送来的消息,并输出到客户端控制台
    class ServerHandler implements Runnable {
        //线程run方法
        public void run() {
            try {
                //输入流(读)
                InputStream in = socket.getInputStream();
                InputStreamReader isr = new InputStreamReader(in,"UTF-8");
                BufferedReader br = new BufferedReader(isr);

                String message = null;
                //读取信息
                while ((message = br.readLine())!=null) {
                    System.out.println(message);
                }

            } catch (Exception e) {
            }
        }
    }

    public static void main(String[] args) {
        try {
            Client2 client2 = new Client2();
            client2.start();
        }catch(Exception e) {
            e.printStackTrace();
            System.out.println("客户端启动失败!");
        }
    }

}

使用Socket实现简单的私聊功能_第1张图片

你可能感兴趣的:(使用Socket实现简单的私聊功能)