多对多聊天案例--综合实践

聊天的大致流程图
在这里插入图片描述
一、创建服务端

//聊天程序,需要用上线程安全
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ConcurrentHashMap;//HashMap查找快
import java.util.concurrent.ConcurrentLinkedDeque;

public class ChatServer {
    //1.在类中添加Socket集合和消息队列

    /**
     * 服务器端口常量
     */
    private static final int port = 9999;

    /**
     * 监听
     */
    public void start(){

        new Thread ( new SendService () ).start ();
        //启动发送线程

        ServerSocket serverSocket = null;
        Socket client = null;
        try {
            //申请端口
            serverSocket = new ServerSocket ( port );
            //监听
            while (true) {
                //监听客户端连接
                System.out.println ("开始监听新的客户端连接...");
                client = serverSocket.accept ();
                System.out.println ("监听客户端【"+ client.getInetAddress ().getHostAddress ()+":"+
                        client.getPort ()+"】");
                //提供消息服务线程
                new ReceiveService ( client ).start ();
                //把socket放进客户socket集合,以便发送线程使用
                String key = client.getInetAddress ().getHostAddress ()+":"+client.getPort ();

                allCustomer.put (key,client );
                //监听下一个
            }
        } catch (IOException e) {
            e.printStackTrace ();
        }

    }
    /**
     * 所有客户端连接集合
     */
    private ConcurrentHashMap<String,Socket> allCustomer = new ConcurrentHashMap <> (  );

    /**
     * 存放消息的队列
      */
    private ConcurrentLinkedDeque<String> messageQueue = new ConcurrentLinkedDeque <> (  );

    /**
     * 创建发送线程
     */
    private class SendService implements Runnable{

        @Override
        public void run () {
            try {
                PrintWriter pw = null;
               while (true){
                   //取消息队列中的消息
                   String mesg = messageQueue.poll ();
                   synchronized (messageQueue) {
                       if (mesg != null){
                           //遍历客户端连接
                           for (Socket socket : allCustomer.values ()) {
                               //创建字符输出流半配网络字节流
                               pw = new PrintWriter (  socket.getOutputStream () );
                               //向客户端发送消息
                               pw.println ( mesg );
                               pw.flush ();
                           }
                        }else {
                          //休息
                           messageQueue.wait ();
                       }
                   }
                   //到队列里面取下一条消息
                }
            } catch (Exception e) {
                e.printStackTrace ();
            }
        }
    }
    //2.创建接受线程,离开ChatServer类没有利用价值,所以写成内部类
    private class ReceiveService extends Thread{
//        /**
//         * 持有消息队列的引用
//         * 内部类因为可以直接访问外部类,所以没必要在创建引用
//         */

        /**
         *  3.接受每个线程的客户端服务
         */
        //客户端的套接字
        private Socket client = null;
        public ReceiveService(Socket client){
            this.client = client;
        }
        public void run(){
            //因为接收字符所以选择字符流,并且Buffer字符流的readLine()接收
            BufferedReader br = null;
            try {
                //注意socket只能得到字节流,所以把它包装成字符流得用InputStreamReader再包装一下
                br = new BufferedReader (
                        new InputStreamReader ( client.getInputStream () ) );
                while (true) {
                    //接收消息
                    System.out.println ("等待接收客户端【"+ client.getInetAddress ().getHostAddress ()+"消息");
                    String mesg = br.readLine ();
                    System.out.println ("接收客户端【"+ client.getInetAddress ().getHostAddress ()+"消息【"+mesg+"】");
                    //放入消息队列
                    synchronized (messageQueue) {   //同步监视器
                        messageQueue.offer ( mesg );
                        messageQueue.notify ();
                    }
                    //放入下一条
                }
            } catch (IOException e) {
                e.printStackTrace ();
            }
        }
    }
}

二、创建客户端

import util.JSONUtil;
import vo.MessageVo;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Date;
import java.util.Scanner;

public class ChatClient {
    /**
     * 聊天服务器的端口
     */
    private String adr = "127.0.0.1";
    Socket s = null;
    /**
     * 聊天服务的端口
     */
    private int port = 9999;
    public void start(){
        try {
            //客户知道服务器的地址和端口
            while (true) {
                s = new Socket (adr,port);
                //启动两个地址和端口,直接创建套接字
                new ReceiveService ().start ();
                new SendService ().start ();
            }
        } catch (Exception e) {
            e.printStackTrace ();
        }
    }

    /**
     * 创建键盘监听
     */
     public class SendService extends Thread{
        PrintWriter pw = null;
         public void run(){
             while (true) {
                 Scanner scanner = new Scanner ( System.in );
                 String mesg = scanner.nextLine ();
                 MessageVo vo = new MessageVo (mesg,new Date() );
                 String jsonStr = JSONUtil.obj2json ( vo );
                 try {
                     pw = new PrintWriter ( s.getOutputStream ());
                 } catch (IOException e) {
                     e.printStackTrace ();
                 }
                 pw.println ( mesg );
                 pw.flush ();
             }
         }
    }

    /**
     * 创建监听服务消息线程
     */
    private class ReceiveService extends Thread{
        private BufferedReader br = null;
        public void run(){
            try {
                while (true) {
                    br = new BufferedReader (
                            new InputStreamReader ( s.getInputStream() ) );
                    //监听服务器 发送来的json字符串
                    String jsonStr = br.readLine ();
//                    json串转换成对象
                    MessageVo mvo = JSONUtil.jsonobj ( jsonStr,MessageVo.class );
                    System.out.println (mvo.getMesg ()+mvo.getDate ());
                }
            } catch (Exception e) {
                e.printStackTrace ();
            }

        }
    }
}

三、创建消息类

import java.util.Date;


public class MessageVo {
    private String mesg;
    private Date date;

    public MessageVo (String mesg, Date date) {
        this.mesg = mesg;
        this.date = date;
    }

    public void MessageVo(){

    }
    public String getMesg () {
        return mesg;
    }

    public void setMesg (String mesg) {
        this.mesg = mesg;
    }

    public Date getDate () {
        return date;
    }

    public void setDate (Date date) {
        this.date = date;
    }
}

四、创建JsonUtil类
注意:该类的创建实际上是按照net.sf.json.JSONObject包(规范)创建的类

import net.sf.json.JSONObject;

public class JSONUtil {
    /**
     * 对象转json的方法
     * @return
     */
    public static String obj2json(Object obj){
        JSONObject object = JSONObject.fromObject ( obj );
        return object.toString ();
    }

    /**
     * 把json串转成对象的方法
     */
    public static <T> T jsonobj(String jsonStr,Class<T> t){
        JSONObject object = JSONObject.fromObject ( jsonStr );
        return (T) JSONObject.toBean ( object,t );
    }
}

五、开启服务端

public class ServerStart {
    public static void main (String[] args) {
        new ChatServer ().start();
    }
}

六、开启客户端

public class ClientStart {
    public static void main (String[] args) {
        new ChatClient ().start ();
    }
}

五、运行结果
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值