66 网络编程(五)——TCP多线程实现多人聊天室
思路
- 客户端读写各一个类,可以使内部类,实现Runnable。读写类都与服务器端建立连接,一个收,一个发。
- 客户端实现接收和转发。多线程实现每个客户端的连接(使与各客户端的连接独立)。
- 服务器端中创建一个公共缓冲池,用于存放消息。通过服务器中的转发方法转发给个客户端。
客户端 代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | package _20191218; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.Socket; import java.net.UnknownHostException; import java.util.Scanner; /** * 多人聊天室,客户端,实时发送接收数据,要实现多线程 */ public class TCPMultipleChatClient { public static void main(String[] args) { System.out.println( "-------局域网聊天室-----------" ); Scanner scan1 = new Scanner(System.in); System.out.print( "请输入您的昵称:" ); String username = scan1.nextLine(); String address = "176.195.108.53" ; //服务器地址 int port = 6788 ; //服务器程序端口 Socket client = null ; try { client = new Socket(address,port); System.out.println( "成功登入,可以开始聊天了!" ); System.out.println( "------------------------" ); } catch (UnknownHostException e) { System.err.println( "服务器连接失败" ); } catch (IOException e) { System.err.println( "服务器连接失败" ); } /** * 启动接收器与发送器 */ new Thread( new Sender(client),username).start(); new Thread( new Receiver(client)).start(); } } //发送器:实现Runnable class Sender implements Runnable{ private boolean flag = true ; //服务器存活为 true //输出流 private DataOutputStream dos; //构造器:初始化 public Sender(Socket client) { try { dos = new DataOutputStream(client.getOutputStream()); } catch (IOException e) { System.err.println( "服务器未开启,连接失败" ); } } public void sendMessage() { Scanner scan = new Scanner(System.in); String message = scan.nextLine(); try { dos.writeUTF(Thread.currentThread().getName()+ ":" +message); dos.flush(); } catch (IOException e) { System.err.println( "Sender:服务器关闭" ); flag = false ; } } public void run() { while (flag) { sendMessage(); try { Thread.sleep( 500 ); } catch (InterruptedException e) { e.printStackTrace(); } } } } //接收器:实现Runnable class Receiver implements Runnable{ private boolean flag = true ; //服务器存活为 true //输入流 private DataInputStream dis; public Receiver(Socket client) { try { dis = new DataInputStream(client.getInputStream()); } catch (IOException e) { e.printStackTrace(); } } //读取消息 public void readMessage() { try { System.out.println(dis.readUTF()); } catch (IOException e) { System.err.println( "Reciver:服务器关闭" ); flag = false ; } } public void run() { while (flag) { readMessage(); try { Thread.sleep( 500 ); } catch (InterruptedException e) { e.printStackTrace(); } } } } //} |
服务器端 代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | package _20191218; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.util.Scanner; /** * 多人聊天室,服务端,实时转发数据 */ public class TCPMultipleChatServer { public static void main(String[] args) { System.out.println( "服务端开启" ); //创建服务器端 ServerSocket server = null ; try { server = new ServerSocket( 6788 ); //服务器端口 } catch (IOException e) { e.printStackTrace(); } //容器 Container container = new Container(); //循环监听 while ( true ) { //阻塞监听连接请求 try { Socket client = server.accept(); System.out.println( "一位用户成功连接" ); container.doCount(); //开启接收器 new Thread( new Receiver(client,container)).start(); //开启转发器 new Thread( new Transmit(client,container)).start(); } catch (IOException e) { e.printStackTrace(); } } } static class Container{ // StringBuffer wrap = new StringBuffer(); static int userCount = 0 ; //当前用户量 private int now = 0 ; //已转发量 private String[] strs = new String[ 1024 ]; //消息队列 private int i = 0 ; //消息计数器 public void add(String message) { strs[i]=message; i++; } public static void doCount() { //用户量加一 userCount++; } public void subUserCount() { //用户量减一 userCount--; } public void reset() { if (now == userCount) { strs = new String[ 1024 ]; now = 0 ; } } } static class Receiver implements Runnable{ private boolean flag = true ; private Container container; private DataInputStream dis; public Receiver(Socket client,Container container) { this .container = container; try { dis = new DataInputStream(client.getInputStream()); } catch (IOException e) { e.printStackTrace(); } } //读取消息 public void readMessage() { try { //存入容器 String str = "" ; if (!(str = dis.readUTF()).equals( "" )) { container.add(str); } } catch (IOException e) { flag = false ; System.err.println( "Read:用户已离开会话" ); container.subUserCount(); } } public void run() { while (flag) { readMessage(); } } } //转发 static class Transmit implements Runnable{ private boolean flag = true ; private Container container; private DataOutputStream dos; public Transmit(Socket client, Container container) { this .container = container; try { this .dos = new DataOutputStream(client.getOutputStream()); } catch (IOException e) { flag = false ; System.err.println( "Transmit:用户已离开会话" ); } } public void run() { while (flag) { transmit(); try { Thread.sleep( 500 ); } catch (InterruptedException e) { e.printStackTrace(); } } } public void transmit() { for (String str : container.strs) { try { if (str== null ) { continue ; } System.out.println( "已转发消息:" +str); container.now++; dos.writeUTF(str); dos.flush(); } catch (IOException e) { e.printStackTrace(); } } container.reset(); //转发完后清空 } } } |
演示
服务器端运行一个,客户端运行多个。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步