项目开发||java聊天程序案例

素颜马尾好姑娘i 2021-12-01 12:52 392阅读 0赞

项目实践:

首先,做这个项目的目的主要是为了巩固java学习的整个基础,包括面向对象的思想,流的应用,线程开发,网络编程的相关基础知识。

为了完成这个项目,首先我们需要清楚他的整个框架,建立聊天程序,是实现端对端的通信,这就需要建立一个服务器,通过这个服务器把多个客户端建立连接,实现聊天。

具体框图,如下:

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0pvY2tMaXU_size_16_color_FFFFFF_t_70

一,服务端

在类中添加消息队列及Socket集合

因为需要给所有客户端发送消息,所以服务器端必须持有所有客户端Socket的集合,生产和消费消息数据需要一个消息队列,所以服务器还必须定义一个消息队列。

  1. package edu.xalead.server;
  2. import java.net.Socket;
  3. import java.util.concurrent.ConcurrentHashMap;
  4. import java.util.concurrent.ConcurrentLinkedQueue;
  5. public class ChatServer {
  6. /**
  7. * 客户端连接集合
  8. */
  9. private ConcurrentHashMap<String, Socket> allCustomer = new ConcurrentHashMap<>();
  10. /**
  11. * 存放消息的队列
  12. */
  13. private ConcurrentLinkedQueue<String> messageQueue = new ConcurrentLinkedQueue<>();
  14. }

创建接收线程

离开ChatServer类没有利用价值,所以我这里写成内部类

  1. package edu.xalead.server;
  2. import java.net.Socket;
  3. import java.util.concurrent.ConcurrentHashMap;
  4. import java.util.concurrent.ConcurrentLinkedQueue;
  5. public class ChatServer {
  6. /**
  7. * 所以客户端连接集合
  8. */
  9. private ConcurrentHashMap<String, Socket> allCustomer = new ConcurrentHashMap<>();
  10. /**
  11. * 存放消息的队列
  12. */
  13. private ConcurrentLinkedQueue<String> messageQueue = new ConcurrentLinkedQueue<>();
  14. /**
  15. * 创建接收线程
  16. * 内部类因为已经可以访问外部类的所有属性和方法,所以没必要再创建
  17. */
  18. private class ReceiveService extends Thread{
  19. // /**
  20. // * 持有消息队列的引用
  21. // * 内部类因为已经可以访问外部类的所有属性和方法,所以没必要再创建引用
  22. // */
  23. // private ConcurrentLinkedQueue<String> messageQueue = null;
  24. // private ReceiveService(ConcurrentLinkedQueue<String> messageQueue){
  25. // this.messageQueue = messageQueue;
  26. // }
  27. public void run(){
  28. }
  29. }
  30. }

接收客户消息

每个接收线程只能为一个特定客户服务,必须持有这个客户的Socket,所以在接收线程中添加客户的Socket引用

  1. //客户端的套接字
  2. private Socket client = null;
  3. public ReceiveService(Socket client){
  4. this.client = client;
  5. }

下面我们先把接收线程的具体工作放一下,思考接收线程中的Socket怎么得到呢?

显然,需要编写监听客户端的代码吧

添加监听客户端连接的代码

  1. /**
  2. * 监听
  3. */
  4. public void start(){
  5. ServerSocket serverSocket = null;
  6. Socket client = null;
  7. try {
  8. //申请端口
  9. serverSocket = new ServerSocket(port);
  10. while (true) {
  11. //监听客户端连接
  12. System.out.println("开始监听新的客户端连接...");
  13. client = serverSocket.accept();
  14. System.out.println("监听到客户端【" + client.getInetAddress()
  15. .getHostAddress() + ":" + client.getPort() + "】");
  16. //提供消息服务
  17. new ReceiveService(client).start();
  18. //把socket放进客户socket集合,以便发送线程使用
  19. allCustomer.put(client.getInetAddress().getHostAddress(),client);
  20. //监听下一个
  21. }
  22. } catch (Exception e) {
  23. e.printStackTrace();
  24. }
  25. }

完成接收服务线程

  1. public void run(){
  2. //因为接收字符所以选择字符流,并且Buffer字符流的readLine()非常好用,所以选择它
  3. BufferedReader br = null;
  4. try {
  5. //注意socket只能得到字节流,所以要把它包装成字符流得用InputStreamReadedr再包装一下
  6. br = new BufferedReader(
  7. new InputStreamReader(client.getInputStream()));
  8. while (true) {
  9. //接收消息
  10. System.out.println("等待接收客户端【" + client.getInetAddress()
  11. .getHostAddress() + "】消息");
  12. String mesg = br.readLine();
  13. System.out.println("接收到客户端【" + client.getInetAddress()
  14. .getHostAddress() + "】消息【" + mesg + "】");
  15. //放入消息队列
  16. messageQueue.offer(mesg);
  17. //接收下一条
  18. }
  19. } catch (Exception e) {
  20. e.printStackTrace();
  21. }
  22. }
  23. }

定义发送线程

  1. /**
  2. * 创建发送线程
  3. */
  4. private class SendService implements Runnable{
  5. @Override
  6. public void run() {
  7. try {
  8. PrintWriter pw = null;
  9. while (true) {
  10. //取消息队列中的消息
  11. String mesg = messageQueue.poll();
  12. if(mesg != null) {
  13. //遍历客户连接
  14. for (Socket socket : allCustomer.values()) {
  15. //创建字符输出流半配网络字节流
  16. pw = new PrintWriter(socket.getOutputStream());
  17. //向客户端发送消息
  18. pw.println(mesg);
  19. pw.flush();
  20. }
  21. //到队列里取下一条消息
  22. }
  23. }
  24. } catch (Exception e) {
  25. e.printStackTrace();
  26. }
  27. }
  28. }

启动发送消息的线程

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0pvY2tMaXU_size_16_color_FFFFFF_t_70 1

发送消息的线程在服务器启动时开启就可以

思考线程协作的问题

如果不考虑线程协作,那么发送消息线程在消息队列为空的时候仍然会做无意义循环,浪费宝贵的CPU时间片

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0pvY2tMaXU_size_16_color_FFFFFF_t_70 2

所以我们要用线程协作解决这个问题。首先要添加同步块,因为消息队列是所有线程监控的同一对象,所以用它作为同步监视器

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0pvY2tMaXU_size_16_color_FFFFFF_t_70 3
切记要注意同步块的范围,如果同步锁定紫色框选范围,则只要有一个线程br.readLine()会等待客户消息,导致所有接收消息的线程无法进入同步块,无法执行接收消息的工作

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0pvY2tMaXU_size_16_color_FFFFFF_t_70 4

最后添加协作代码,当消息队列为空时,发送线程进入休眠状态

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0pvY2tMaXU_size_16_color_FFFFFF_t_70 5

当接收消息线程接收到消息并放入消息队列,则唤醒发送线程

准备把传输数据改为json传输

创建vo对象

  1. public class MessageVO {
  2. private String mesg;
  3. private Date date;
  4. public MessageVO() {
  5. }
  6. public MessageVO(String mesg, Date date) {
  7. this.mesg = mesg;
  8. this.date = date;
  9. }
  10. public String getMesg() {
  11. return mesg;
  12. }
  13. public void setMesg(String mesg) {
  14. this.mesg = mesg;
  15. }
  16. public Date getDate() {
  17. return date;
  18. }
  19. public void setDate(Date date) {
  20. this.date = date;
  21. }
  22. }

创建JSON和对象互转工具类

  1. package edu.xalead.util;
  2. import net.sf.json.JSONObject;
  3. public class JSONUtil {
  4. /**
  5. * 对象转json的方法
  6. * @return
  7. */
  8. public static String obj2json(Object obj){
  9. JSONObject ob = JSONObject.fromObject(obj);
  10. return ob.toString();
  11. }
  12. /**
  13. * 把json串转成对象的方法
  14. * @return
  15. */
  16. public static <T> T json2obj(String jsonStr,Class<T> t){
  17. JSONObject object = JSONObject.fromObject(jsonStr);
  18. return (T)JSONObject.toBean(object,t);
  19. }
  20. /**
  21. *创建学生对象
  22. */
  23. @Test
  24. public void test1() {
  25. //创建学生对象
  26. Student s = new Student ();
  27. s.setName ("胡歌");
  28. s.setId (140137);
  29. s.setAge (36);
  30. Address adr = new Address ();
  31. adr.setHomeAddr ("上海市徐汇区");
  32. adr.setSchoolAddr ("上海戏剧学院");
  33. s.setAddress (adr);
  34. System.out.println (JSONUtil.obj2json(s));
  35. String jsonStr = "{\"address\":{\"homeAddr\":\"上海市徐汇区\",\"schoolAddr\":\"上海戏剧学院\"},\"age\":36,\"id\":140137,\"name\":\"胡歌\"}";
  36. Student ss = JSONUtil.json2obj(jsonStr,Student.class);//toBean()方法把中间对象转换成对象
  37. System.out.println (ss);
  38. }
  39. }

编写服务端启动类

  1. package edu.xalead.server;
  2. public class ServerStart {
  3. public static void main(String[] args) {
  4. new ChatServer().start();
  5. }
  6. }

———完整服务器代码:

chatserver:

  1. package edu.xalead.server;
  2. import java.io.BufferedReader;
  3. import java.io.IOException;
  4. import java.io.InputStreamReader;
  5. import java.io.PrintWriter;
  6. import java.net.ServerSocket;
  7. import java.net.Socket;
  8. import java.util.concurrent.ConcurrentHashMap;
  9. import java.util.concurrent.ConcurrentLinkedQueue;
  10. public class ChatServer {
  11. /**
  12. * 服务器端口常量
  13. */
  14. private static final int port = 5371;
  15. /**
  16. * 监听
  17. */
  18. public void start(){
  19. //启动发送消息线程
  20. new Thread(new SendService()).start();
  21. ServerSocket serverSocket = null;
  22. Socket client = null;
  23. try {
  24. //申请端口
  25. serverSocket = new ServerSocket(port);
  26. while (true) {
  27. //监听客户端连接
  28. System.out.println("开始监听新的客户端连接...");
  29. client = serverSocket.accept();
  30. System.out.println("监听到客户端【" + client.getInetAddress().getHostAddress() + ":" +
  31. client.getPort() + "】");
  32. //提供消息服务线程
  33. new ReceiveService(client).start();
  34. //把socket放进客户socket集合,以便发送线程使用
  35. String key = client.getInetAddress().getHostAddress() + ":" + client.getPort();
  36. allCustomer.put(key,client);
  37. //监听下一个
  38. }
  39. } catch (Exception e) {
  40. e.printStackTrace();
  41. }
  42. }
  43. /**
  44. * 所以客户端连接集合
  45. */
  46. private ConcurrentHashMap<String, Socket> allCustomer = new ConcurrentHashMap<>();
  47. /**
  48. * 存放消息的队列
  49. */
  50. private ConcurrentLinkedQueue<String> messageQueue = new ConcurrentLinkedQueue<>();
  51. /**
  52. * 创建发送线程
  53. */
  54. private class SendService implements Runnable{
  55. @Override
  56. public void run() {
  57. try {
  58. PrintWriter pw = null;
  59. while (true) {
  60. //取消息队列中的消息
  61. String mesg = messageQueue.poll();
  62. synchronized (messageQueue) {
  63. if(mesg != null) {
  64. //遍历客户连接
  65. for (Socket socket : allCustomer.values()) {
  66. //创建字符输出流半配网络字节流
  67. pw = new PrintWriter(socket.getOutputStream());
  68. //向客户端发送消息
  69. pw.println(mesg);
  70. pw.flush();
  71. }
  72. //到队列里取下一条消息
  73. }else{
  74. //休息
  75. messageQueue.wait();
  76. }
  77. }
  78. }
  79. } catch (Exception e) {
  80. e.printStackTrace();
  81. }
  82. }
  83. }
  84. /**
  85. * 创建接收线程
  86. */
  87. private class ReceiveService extends Thread{
  88. // /**
  89. // * 持有消息队列的引用
  90. // */
  91. // private ConcurrentLinkedQueue<String> messageQueue = null;
  92. // private ReceiveService(ConcurrentLinkedQueue<String> messageQueue){
  93. // this.messageQueue = messageQueue;
  94. // }
  95. //客户端的套接字
  96. private Socket client = null;
  97. public ReceiveService(Socket client){
  98. this.client = client;
  99. }
  100. public void run(){
  101. //因为接收字符所以选择字符流,并且Buffer字符流的readLine()非常好用,所以选择它
  102. BufferedReader br = null;
  103. try {
  104. //注意socket只能得到字节流,所以要把它包装成字符流得用InputStreamReadedr再包装一下
  105. br = new BufferedReader(
  106. new InputStreamReader(client.getInputStream()));
  107. while (true) {
  108. //接收消息
  109. System.out.println("等待接收客户端【" + client.getInetAddress().getHostAddress() + "】消息");
  110. String mesg = br.readLine();
  111. System.out.println("接收到客户端【" + client.getInetAddress().getHostAddress() + "】消息【" + mesg + "】");
  112. //放入消息队列
  113. synchronized (messageQueue) {
  114. messageQueue.offer(mesg);
  115. messageQueue.notify();
  116. }
  117. //接收下一条
  118. }
  119. } catch (Exception e) {
  120. e.printStackTrace();
  121. }
  122. }
  123. }
  124. }

MessageVo:

  1. package edu.xalead.vo;
  2. import java.util.Date;
  3. public class MessageVo {
  4. private String mesg;
  5. private Date data;
  6. public MessageVo(){
  7. }
  8. public MessageVo(String mesg, Date date){
  9. this.mesg=mesg;
  10. this.data=date;
  11. }
  12. public String getMesg() {
  13. return mesg;
  14. }
  15. public void setMesg(String mesg) {
  16. this.mesg = mesg;
  17. }
  18. public Date getDate() {
  19. return data;
  20. }
  21. public void setDate(Date data) {
  22. this.data = data;
  23. }
  24. }

Stuent类:

  1. package test.edu.xalead;
  2. public class Student {
  3. private int id;
  4. private String name;
  5. private int age;
  6. private Address address;
  7. @Override
  8. public String toString() {
  9. return "Student{" +
  10. "id=" + id +
  11. ", name='" + name + '\'' +
  12. ", age=" + age +
  13. ", address=" + address +
  14. '}';
  15. }
  16. public Address getAddress() {
  17. return address;
  18. }
  19. public void setAddress(Address address) {
  20. this.address = address;
  21. }
  22. public int getId() {
  23. return id;
  24. }
  25. public void setId(int id) {
  26. this.id = id;
  27. }
  28. public String getName() {
  29. return name;
  30. }
  31. public void setName(String name) {
  32. this.name = name;
  33. }
  34. public int getAge() {
  35. return age;
  36. }
  37. public void setAge(int age) {
  38. this.age = age;
  39. }
  40. }

Address类:

  1. package test.edu.xalead;
  2. public class Address {
  3. private String homeAddr;
  4. private String schoolAddr;
  5. @Override
  6. public String toString() {
  7. return "Address{" +
  8. "homeAddr='" + homeAddr + '\'' +
  9. ", schoolAddr='" + schoolAddr + '\'' +
  10. '}';
  11. }
  12. public String getHomeAddr() {
  13. return homeAddr;
  14. }
  15. public void setHomeAddr(String homeAddr) {
  16. this.homeAddr = homeAddr;
  17. }
  18. public String getSchoolAddr() {
  19. return schoolAddr;
  20. }
  21. public void setSchoolAddr(String schoolAddr) {
  22. this.schoolAddr = schoolAddr;
  23. }
  24. }

Test类:

  1. package edu.xalead.util;
  2. import net.sf.json.JSONObject;
  3. public class JSONUtil {
  4. /**
  5. * 对象转json的方法
  6. * @return
  7. */
  8. public static String obj2json(Object obj){
  9. JSONObject ob = JSONObject.fromObject(obj);
  10. return ob.toString();
  11. }
  12. /**
  13. * 把json串转成对象的方法
  14. * @return
  15. */
  16. public static <T> T json2obj(String jsonStr,Class<T> t){
  17. JSONObject object = JSONObject.fromObject(jsonStr);
  18. return (T)JSONObject.toBean(object,t);
  19. }
  20. /**
  21. *创建学生对象
  22. */
  23. @Test
  24. public void test1() {
  25. //创建学生对象
  26. Student s = new Student ();
  27. s.setName ("胡歌");
  28. s.setId (140137);
  29. s.setAge (36);
  30. Address adr = new Address ();
  31. adr.setHomeAddr ("上海市徐汇区");
  32. adr.setSchoolAddr ("上海戏剧学院");
  33. s.setAddress (adr);
  34. System.out.println (JSONUtil.obj2json(s));
  35. String jsonStr = "{\"address\":{\"homeAddr\":\"上海市徐汇区\",\"schoolAddr\":\"上海戏剧学院\"},\"age\":36,\"id\":140137,\"name\":\"胡歌\"}";
  36. Student ss = JSONUtil.json2obj(jsonStr,Student.class);//toBean()方法把中间对象转换成对象
  37. System.out.println (ss);
  38. }
  39. }

启动类:

  1. package edu.xalead.server;
  2. public class ServerStart {
  3. public static void main(String[] args) {
  4. new ChatServer().start();
  5. }
  6. }

二,客户端

客户端知道服务器的地址和端口,先编写客户端类直连服务器

  1. package edu.xalead.client;
  2. import edu.xalead.util.JSONUtil;
  3. import edu.xalead.vo.MessageVo;
  4. import java.io.BufferedReader;
  5. import java.io.IOException;
  6. import java.io.InputStreamReader;
  7. import java.io.PrintWriter;
  8. import java.net.Socket;
  9. import java.util.Date;
  10. import java.util.Scanner;
  11. public class ChatClient {
  12. /**
  13. * 聊天服务器的地址
  14. */
  15. private String addr = "127.0.0.1";
  16. /**
  17. * 连接服务器的套接字
  18. */
  19. Socket s = null;
  20. /**
  21. * 聊天服务的端口
  22. */
  23. private int port = 5371;
  24. /**
  25. * 启动客户端
  26. */
  27. public void start(){
  28. try {
  29. //客户知道服务器的地址和端口,直接创建套接字
  30. s = new Socket(addr,port);
  31. //启动两个监听服务线程
  32. new ReceiveService().start();
  33. new SendService().start();
  34. } catch (Exception e) {
  35. e.printStackTrace();
  36. }
  37. }
  38. /**
  39. * 创建监听键盘的线程
  40. */
  41. private class SendService extends Thread{
  42. private PrintWriter pw = null;
  43. public void run(){
  44. try {
  45. Scanner scanner = new Scanner(System.in);
  46. while (true) {
  47. //接收键盘消息
  48. String mesg = scanner.nextLine();
  49. //封装MessageVO
  50. MessageVo vo = new MessageVo(mesg, new Date());
  51. //解析成json串
  52. String jsonStr = JSONUtil.obj2json(vo);
  53. //发送到服务器
  54. pw = new PrintWriter(s.getOutputStream());
  55. pw.println(jsonStr);
  56. pw.flush();
  57. //监听键盘下一条
  58. }
  59. } catch (Exception e) {
  60. e.printStackTrace();
  61. }
  62. }
  63. }
  64. /**
  65. * 创建监听服务器消息线程
  66. */
  67. private class ReceiveService extends Thread{
  68. private BufferedReader br = null;
  69. public void run(){
  70. try {
  71. while (true) {
  72. br = new BufferedReader(
  73. new InputStreamReader(s.getInputStream()));
  74. //监听服务器发送过来的json字符串
  75. String jsonStr = br.readLine();
  76. //json串转换成对象
  77. MessageVo mvo = JSONUtil.json2obj(jsonStr,MessageVo.class);
  78. //在控制台输出
  79. System.out.println("info:" + mvo.getMesg() + " 【时间:" + mvo.getDate() + "】");
  80. //再监听有没有下一个
  81. }
  82. } catch (Exception e) {
  83. e.printStackTrace();
  84. }
  85. }
  86. }
  87. }

客户端要做两件事:

  • 1.监听服务器返回的消息,并输出到控制台
  • 2.监听键盘消息,并发向服务器

    很显然,这里需要两个客户线程

创建客户端接收线程

  • 1.监听服务器返回的消息,并输出到控制台,因为离开客户端没有复用价值,所以我们也是写成ChatClient类的内部类

    /**

    1. * 创建监听服务器消息线程
    2. */
    3. private class ReceiveService extends Thread{
    4. private BufferedReader br = null;
    5. public void run(){
    6. try {
    7. while (true) {
    8. br = new BufferedReader(
    9. new InputStreamReader(s.getInputStream()));
    10. //监听服务器发送过来的json字符串
    11. String jsonStr = br.readLine();
    12. //json串转换成对象
    13. MessageVO mvo = JSONUtil.json2obj(jsonStr,MessageVO.class);
    14. //在控制台输出
    15. System.out.println("info:" + mvo.getMesg() + " 【时间:】" + mvo.getDate());
    16. //再监听有没有下一个
    17. }
    18. } catch (Exception e) {
    19. e.printStackTrace();
    20. }
    21. }
    22. }

监听键盘消息,并发向服务器

  1. /**
  2. * 创建监听键盘的线程
  3. */
  4. private class SendService extends Thread{
  5. private PrintWriter pw = null;
  6. public void run(){
  7. try {
  8. Scanner scanner = new Scanner(System.in);
  9. while (true) {
  10. //接收键盘消息
  11. String mesg = scanner.nextLine();
  12. //封装MessageVO
  13. MessageVO vo = new MessageVO(mesg, new Date());
  14. //解析成json串
  15. String jsonStr = JSONUtil.obj2json(vo);
  16. //发送到服务器
  17. pw = new PrintWriter(s.getOutputStream());
  18. pw.println(jsonStr);
  19. pw.flush();
  20. //监听键盘下一条
  21. }
  22. } catch (Exception e) {
  23. e.printStackTrace();
  24. }
  25. }
  26. }

最后,编写客户端的启动类

  1. package edu.xalead.client;
  2. public class ClientStart {
  3. public static void main(String[] args) {
  4. new ChatClient().start();
  5. }
  6. }

-———完整客户端代码:

ChatClient类:

  1. package edu.xalead.client;
  2. import edu.xalead.util.JSONUtil;
  3. import edu.xalead.vo.MessageVo;
  4. import java.io.BufferedReader;
  5. import java.io.IOException;
  6. import java.io.InputStreamReader;
  7. import java.io.PrintWriter;
  8. import java.net.Socket;
  9. import java.util.Date;
  10. import java.util.Scanner;
  11. public class ChatClient {
  12. /**
  13. * 聊天服务器的地址
  14. */
  15. private String addr = "127.0.0.1";
  16. /**
  17. * 连接服务器的套接字
  18. */
  19. Socket s = null;
  20. /**
  21. * 聊天服务的端口
  22. */
  23. private int port = 5371;
  24. /**
  25. * 启动客户端
  26. */
  27. public void start(){
  28. try {
  29. //客户知道服务器的地址和端口,直接创建套接字
  30. s = new Socket(addr,port);
  31. //启动两个监听服务线程
  32. new ReceiveService().start();
  33. new SendService().start();
  34. } catch (Exception e) {
  35. e.printStackTrace();
  36. }
  37. }
  38. /**
  39. * 创建监听键盘的线程
  40. */
  41. private class SendService extends Thread{
  42. private PrintWriter pw = null;
  43. public void run(){
  44. try {
  45. Scanner scanner = new Scanner(System.in);
  46. while (true) {
  47. //接收键盘消息
  48. String mesg = scanner.nextLine();
  49. //封装MessageVO
  50. MessageVo vo = new MessageVo(mesg, new Date());
  51. //解析成json串
  52. String jsonStr = JSONUtil.obj2json(vo);
  53. //发送到服务器
  54. pw = new PrintWriter(s.getOutputStream());
  55. pw.println(jsonStr);
  56. pw.flush();
  57. //监听键盘下一条
  58. }
  59. } catch (Exception e) {
  60. e.printStackTrace();
  61. }
  62. }
  63. }
  64. /**
  65. * 创建监听服务器消息线程
  66. */
  67. private class ReceiveService extends Thread{
  68. private BufferedReader br = null;
  69. public void run(){
  70. try {
  71. while (true) {
  72. br = new BufferedReader(
  73. new InputStreamReader(s.getInputStream()));
  74. //监听服务器发送过来的json字符串
  75. String jsonStr = br.readLine();
  76. //json串转换成对象
  77. MessageVo mvo = JSONUtil.json2obj(jsonStr,MessageVo.class);
  78. //在控制台输出
  79. System.out.println("info:" + mvo.getMesg() + " 【时间:" + mvo.getDate() + "】");
  80. //再监听有没有下一个
  81. }
  82. } catch (Exception e) {
  83. e.printStackTrace();
  84. }
  85. }
  86. }
  87. }

启动类:

  1. package edu.xalead.client;
  2. public class ClientStart {
  3. public static void main(String[] args) {
  4. new ChatClient().start();
  5. }
  6. }

三,调试

打开服务器

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0pvY2tMaXU_size_16_color_FFFFFF_t_70 6

打开两个客户端后,服务器

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0pvY2tMaXU_size_16_color_FFFFFF_t_70 7

两个客户端各自发送一条消息:

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0pvY2tMaXU_size_16_color_FFFFFF_t_70 8

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0pvY2tMaXU_size_16_color_FFFFFF_t_70 9

此时,服务器:

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0pvY2tMaXU_size_16_color_FFFFFF_t_70 10

完成聊天通信!

发表评论

表情:
评论列表 (有 0 条评论,392人围观)

还没有评论,来说两句吧...

相关阅读