基于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 }
客户端代码:
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 }