基于Socket实现多人聊天室

当前支持:

1.仅文字

2.加入聊天室提醒

3.退出聊天室提醒

可能出现的BUG:

1.可能出现客户端发送信息后不能及时推送,需要下一个客户端发送信息后一起推送

服务端代码:

  1 package com.example.demo.socket;
  2 
  3 import org.springframework.util.ObjectUtils;
  4 
  5 import java.io.DataInputStream;
  6 import java.io.DataOutputStream;
  7 import java.io.IOException;
  8 import java.net.ServerSocket;
  9 import java.net.Socket;
 10 import java.util.HashMap;
 11 import java.util.Map;
 12 import java.util.concurrent.*;
 13 
 14 public class Server {
 15     public static void main(String[] args) {
 16         //信息队
 17         ConcurrentLinkedQueue str = new ConcurrentLinkedQueue<>();
 18         //连接对,暂未使用
 19         ConcurrentLinkedQueue<Map> socket = new ConcurrentLinkedQueue<>();
 20         //信息接收队
 21         ConcurrentLinkedQueue<Map> ins = new ConcurrentLinkedQueue<>();
 22         //信息发送队
 23         ConcurrentLinkedQueue<Map> outs = new ConcurrentLinkedQueue<>();
 24         //服务端端口号
 25         int port = 6666;
 26         try {
 27             ServerSocket serverSocket = new ServerSocket(port);
 28             //读取信息
 29             new Thread(new Runnable() {
 30                 @Override
 31                 public void run() {
 32                     // 参数 4 可以根据实际服务器cup设置 一般IO密集型设置为 CUP+1
 33                     ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(4);
 34                     while (true) {
 35                         if(!ObjectUtils.isEmpty(ins.peek())) {
 36                             Map in = ins.poll();
 37                             //延迟10毫秒执行,执行周期为  实际线程执行时间+10毫秒
 38                             ScheduledFuture<?> scheduledFuture = scheduledExecutorService.scheduleWithFixedDelay(new Runnable() {
 39                                 @Override
 40                                 public void run() {
 41                                     try {
 42                                         in.put("str", ((DataInputStream) in.get("in")).readUTF());
 43                                         str.add(in);
 44                                     } catch (IOException e) {
 45                                         ((ScheduledFuture)in.get("future")).cancel(true);
 46                                     }
 47                                 }
 48                             }, 10, 10, TimeUnit.MICROSECONDS);
 49                             in.put("future",scheduledFuture);
 50                         }
 51                     }
 52                 }
 53             }).start();
 54             //发送信息
 55             new Thread(new Runnable() {
 56                 @Override
 57                 public void run() {
 58                     while (true) {
 59                         if(!ObjectUtils.isEmpty(str.peek())) {
 60                             Map o = (Map) str.poll();
 61                             for(Map m : outs) {
 62                                 if(!o.get("client").equals(m.get("client"))) {
 63                                     try {
 64                                         ((DataOutputStream)m.get("out")).writeUTF( o.get("client")+":"+o.get("str"));
 65                                     } catch (IOException e) {
 66                                         //异常下线大法,并发送群体下线通知
 67                                         System.out.printf("%s下线了!\n",m.get("client"));
 68                                         Map sv = new HashMap<>();
 69                                         sv.put("client","server");
 70                                         sv.put("str",m.get("client")+"退出聊天室!");
 71                                         str.add(sv);
 72                                         outs.remove(m);
 73                                     }
 74                                 }
 75                             }
 76                         }
 77                     }
 78                 }
 79             }).start();
 80             //循环获取客户端连接
 81             while (true) {
 82                 Socket server = serverSocket.accept();
 83                 Map m = new HashMap<>();
 84                 m.put("socket",socket);
 85                 m.put("in",new DataInputStream(server.getInputStream()));
 86                 m.put("out",new DataOutputStream(server.getOutputStream()));
 87 
 88                 //向客户端发送聊天室名,并获取客户端连接名
 89                 ((DataOutputStream)m.get("out")).writeUTF("6666");
 90                 m.put("client",((DataInputStream)m.get("in")).readUTF());
 91                 System.out.printf("新人%s加入聊天室!\n",m.get("client"));
 92 
 93                 ins.add(m);
 94                 outs.add(m);
 95                 socket.add(m);
 96 
 97                 //发送群体上线通知
 98                 Map sv = new HashMap<>();
 99                 sv.put("client","server");
100                 sv.put("str",m.get("client")+"加入聊天室!");
101                 str.add(sv);
102             }
103         } catch (Exception e) {
104             e.printStackTrace();
105         }
106     }
107 }
Server

客户端代码:

 1 package com.example.demo.socket;
 2 
 3 import java.io.DataInputStream;
 4 import java.io.DataOutputStream;
 5 import java.io.IOException;
 6 import java.net.Socket;
 7 import java.util.Scanner;
 8 
 9 public class Client {
10 
11     public static void main(String[] args) {
12         //服务端 IP
13         String serverName = "localhost";
14         //服务端 端口号
15         int port = 6666;
16         try {
17             Socket client = new Socket(serverName,port);
18             DataInputStream in = new DataInputStream(client.getInputStream());
19             DataOutputStream out = new DataOutputStream(client.getOutputStream());
20             //向服务端发送连接名,并确认服务端收到连接名且返回聊天室名
21             out.writeUTF("client");
22             out.flush();
23             System.out.printf("进入聊天室 %s \n",in.readUTF());
24             try {
25                 new Thread(new Runnable() {
26                     @Override
27                     public void run() {
28                         try {
29                             while (true) {
30                                 System.out.println(in.readUTF());
31                             }
32                         } catch (IOException e) {
33                             e.printStackTrace();
34                         }
35                     }
36                 }).start();
37                 while (true) {
38                     out.writeUTF(new Scanner(System.in).nextLine());
39                     out.flush();
40                 }
41             } finally {
42                 client.close();
43             }
44         } catch (Exception e) {
45             e.printStackTrace();
46         }
47 
48     }
49 }
Client

 

posted on 2021-05-10 17:44  instr  阅读(201)  评论(0编辑  收藏  举报

导航