TCP多人聊天室实现 JSON文件解析

1. TCP多人聊天室实现

1.1 分析

客户端
功能:
    1. 数据发送
    2. 数据接收
技术: 
    1. socket
    2. 输入流和输出流
    3. 多线程,客户端功能模块有两个线程
聊天:
    1. 群聊
    2. 私聊            私聊前缀 @服务器用户ID号:msg
package com.my.chatroom.client;

import com.my.chatroom.utils.CloseUtil;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;

public class Sender implements Runnable {
    private DataOutputStream dop ;
    private BufferedReader br ;
    private boolean connect ;
    /**
     * @param socket
     * @param userName
     */
    public Sender(Socket socket , String userName) {
        try {
            dop = new DataOutputStream(socket.getOutputStream()) ;
            br = new BufferedReader(new InputStreamReader(System.in)) ;
            send(userName);
            connect = true ;
        } catch (IOException e) {
            e.printStackTrace();
            connect = false ;
        }
    }
    /**
     *  从键盘获得输入的消息
     *  @return 返回用户输入的消息字符串
     */
    public String getMessage() {
        String message = null ;
        try {
            message = br.readLine() ;

        } catch (IOException e) {
            e.printStackTrace();
            connect = false ;
            CloseUtil.closeAll(br,dop);
        }
        return message ;
    }
    /**
     *  发送消息给服务器
     *  @param message
     */
    public void send(String message) {
        if (message != null && ! "".equals(message)) {
            try {
                dop.writeUTF(message);
                dop.flush();
            } catch (IOException e) {
                e.printStackTrace();
                connect = false ;
                CloseUtil.closeAll(dop,br);
            }

        }

    }
    /**
     *  线程任务:只要是连接状态就不停获取和发送消息
     */
    @Override
    public void run() {
        while (connect) {
            send(getMessage());
        }

    }
}

package com.my.chatroom.client;

import com.my.chatroom.utils.CloseUtil;

import java.io.DataInputStream;
import java.io.IOException;
import java.net.Socket;

public class Receiver implements Runnable {
    private DataInputStream dis ;
    private boolean connect ;
    /**
     *  根据客户端连接服务器时的Socket对象获取输入流对象
     *  @param socket
     */
    public Receiver(Socket socket) {
        try {
            dis = new DataInputStream(socket.getInputStream()) ;
            connect = true ;
        } catch (IOException e) {
            e.printStackTrace();
            connect = false ;
        }
    }

    /**
     *  接受并展示消息
     */
    public void receive() {
        String message = null ;
        try {
            message = dis.readUTF() ;
        } catch (IOException e) {
            e.printStackTrace();
            connect =false ;
            CloseUtil.closeAll(dis);
        }

        System.out.println(message);

    }
    /**
     *  只要是连接状态就一直接收消息
     */
    @Override
    public void run() {
        while (connect) {
            receive();
        }

    }
}

服务器
功能:
    1. 数据转发
    2. 用户注册
技术:
    1. ServerSocket
    2. 每一个用户对应的Sokcet对象
    3. 多线程同时在线
    4. HashMap<Integer, 用户>
数据转发:        私聊前缀判断        群聊所有人发送
package com.my.chatroom.server;

import com.my.chatroom.utils.CloseUtil;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Collection;
import java.util.HashMap;

public class Server {
    private HashMap<Integer , UserSocket> userMap ;
    private static int count = 0 ;

    public Server() {
        userMap = new HashMap<Integer, UserSocket>() ;
    }
    public void start() throws IOException {
        ServerSocket serverSocket = new ServerSocket(8080) ;
        System.out.println("服务器启动!");
        while (true) {
            Socket socket = serverSocket.accept() ;
            count += 1 ;
            UserSocket userSocket = new UserSocket(count , socket) ;
            userMap.put(count , userSocket) ;
            new Thread(userSocket).start();

        }
    }

    class UserSocket implements Runnable {
        private DataInputStream dis ;
        private DataOutputStream dos ;
        private int userId ;
        private String userName;
        private boolean connect ;
        /**
         *  创建UserSocket对象需要userid和socket对象
         *   @param userid
         *   @param socket
         */
        public UserSocket(int userid , Socket socket) {
            this.userId = userid ;
            try {
                dis = new DataInputStream(socket.getInputStream()) ;
                dos = new DataOutputStream(socket.getOutputStream()) ;
                connect = true ;
            } catch (IOException e) {
                e.printStackTrace();
                connect = false;
            }

            try {
                assert dis != null ;
                this.userName = dis.readUTF() ;
                chatStyle("ID:" + this.userId + " " + this.userName + "来到直播间", true);
                send("欢迎来到聊天室!");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        /**
         *  接收用户发送的消息并做转发处理
         *   @return
         */
        public String receice() {
            String message = null ;
            try {
                message = dis.readUTF() ;

            } catch (IOException e) {
                e.printStackTrace();
                connect = false ;
                CloseUtil.closeAll(dis , dos);
            }
            return message ;
        }
        /**
         *  转发消息给用户
         *  @param message
         */
        public void send(String message) {
            try {
                dos.writeUTF(message);
                dos.flush();
            } catch (IOException e) {
                e.printStackTrace();
                connect = false;
                CloseUtil.closeAll(dis , dos);
            }

        }
        /**
         *  判断聊天方式:私聊或者群聊,并判断是否是系统消息
         *   @param message
         *   @param sys
         */
        public void chatStyle(String message , boolean sys){
            if (message.startsWith("@") && message.contains(":")) {
                Integer id = Integer.parseInt(message.substring(1,message.indexOf(":"))) ;
                String newMessage = message.substring(message.indexOf(":")) ;
                UserSocket userSocket = userMap.get(id) ;
                if (userSocket != null) {
                    userSocket.send("ID" + this.userId + " " + this.userName + "悄悄对你说:" + message);
                }
            } else {
                Collection<UserSocket> userSockets = userMap.values() ;
                for (UserSocket userSocket : userSockets) {
                    if (userSocket != this) {
                        if (sys) {
                            System.out.println("系统公告:" + message);
                        } else {
                            System.out.println("ID" + this.userId + " " + this.userName + message);
                        }
                    }
                }
            }

        }

        @Override
        public void run() {
            while (connect) {
                chatStyle(receice() , false);
            }

        }
    }

    public static void main(String[] args) {
        Server server = new Server() ;
        try {
            server.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}


1.2 客户端实现

数据发送: 使用输出流发送数据给服务器 遵从Runnable接口
数据接收: 使用输入流从服务器端接收数据 遵从Runnable接口
客户端主方法: 用户名提交 数据发送 数据接收 多线程启动

package com.my.chatroom.client;

import com.my.chatroom.utils.CloseUtil;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Client {
    public static void main(String[] args) {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in)) ;
        Socket socket = null ;
        String name = null ;

        try {
            System.out.println("请输入您的用户名:");
            name = br.readLine() ;
            if (!"".equals(name)) {
                return;
            }
            socket = new Socket(InetAddress.getLocalHost() , 8080) ;
        } catch (IOException e) {
            System.out.println("连接失败!");
            CloseUtil.closeAll(br);
            System.exit(0);
        }
        ExecutorService pool = Executors.newFixedThreadPool(2) ;
        pool.submit(new Sender(socket , name)) ;
        pool.submit(new Receiver(socket)) ;
    }
}

1.3 资源关闭问题

代码中操作了大量的输入流和输出流,这里都需要进行关闭操作。
DataInputStream, DataOutputStream, BufferedReader, Socket
以上这些资源都是Closeable接口的实现类,都有对应的 Close方法
封装一个工具类: 提供一个closeAll方法,参数为符合Closeable接口的 实现类对象。
这里可以考虑可变长参数
Closeable… closeable
可变长参数在方法中使用的过程里面是对应一个数组,这 里完成可以使用增强for来使用
工具类名: CloseUtil public static void closeAll(Closeable… closeable)

package com.my.chatroom.utils;

import java.io.Closeable;
import java.io.IOException;

public class CloseUtil {
    public static void closeAll(Closeable... closeables) {
        try {
            for (Closeable closeable : closeables) {
                if (closeable != null) {

                    closeable.close();
                }
            }
        }catch (IOException e) {
                    e.printStackTrace();
        }
    }
}

1.4 功能拓展

1. 用户退出
用户输入指定字段之后可以退出    客户端Socket服务    服务端Socket服务    涉及资源关闭,线程关闭
2. 用户异常退出
在运行过程中发现问题,需要及时处理,关闭对应的资 源,终止对应的线程
3. 服务器保存所有的聊天记录

2. JSON

2.1 JSON格式概述

JSON JavaScript Object Notation(JavaScript Object Notation,JavaScript对象表示法,读作/ˈdʒeɪsən/)是一种由道格拉斯·克罗克福特构想 和设计、轻量级的数据交换语言,该语言以易于让人阅读的文 字为基础,用来传输由属性值或者序列性的值组成的数据对 象。尽管JSON是JavaScript的一个子集,但JSON是独立于语 言的文本格式,并且采用了类似于C语言家族的一些习惯

2.2 数据格式

2.2.1 JSON对象

特征:
1. 数据形式键值对形式 “键”:值
2. 数据支持 字符串,数字,true false
3. {} 大括号以内的数据

2.2.2 JSON对象数组

特征:
1. 数据使用[]包含
2. 在[]都是JSON格式对象
3. 每一个对象之间使用逗号隔开,同时最后一个元素不 需要逗号

2.2.3 JSON数据验证

2.3 解析JSON格式工具

常用的工具: Gson,fastjson, Jackson 以上都是第三方工具,需要导入对应的jar包按使用 XML导包

2.3.1 FastJson内容

JSON核心类
JSON核心类提供解析和转化方法,用于解析JSON数据格 式,同时用于转换类对象到JSON格式,该类对象需要符合 JavaBean规范
–| JSONArray 存在按照键值对方式解析获取数据,同时存在一定 的List方法
–| JSONObject 获取对应的类对象,指定键值对对应数据的方法

package com.my.demo1;
/*
完成一个符合JavaBean规范的类
*/
public class Student {
    private String name;
    private Integer age;

    // 这里根据需要完成对应的Setter和getter方法

    public Student() {
    }

    public Student(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

package com.my.demo1;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import java.util.ArrayList;
import java.util.List;

public class Demo1 {
    public static void main(String[] args) {
        ArrayList<Student> students = new ArrayList<>() ;
        students.add(new Student("飞哥" , 22)) ;
        students.add(new Student("小明" , 22)) ;
        students.add(new Student("老段" , 23)) ;
        students.add(new Student("羽羽" , 21)) ;
        String str = JSON.toJSONString(students) ;
        System.out.println(str);
        System.out.println("----------------------------------------------------------------------");
        Student student = new Student("自豪" , 23) ;
        String str2 = JSON.toJSONString(student) ;
        System.out.println(str2);
        Student student2 = JSON.parseObject(str2 , Student.class) ;
        System.out.println(student2);
        JSONObject jsonObject = JSON.parseObject(str2) ;
        String name = jsonObject.getString("name") ;
        Integer age = jsonObject.getInteger("age") ;
        System.out.println(name);
        System.out.println(age);
        System.out.println("----------------------------------------------------------------------");
        JSONArray objects = JSON.parseArray(str) ;
        System.out.println(objects);
        for (Object object : objects) {
            JSONObject jsonObject1 = (JSONObject) object;
            System.out.println(jsonObject1.getString("name"));
            System.out.println(jsonObject1.getInteger("age"));

        }
        Student student3 = objects.getObject(1 , Student.class) ;
        System.out.println(student3);
        List<Student> students2 = objects.toJavaList(Student.class) ;
        for (Student stu : students2) {
            System.out.println(stu);
        }


    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值