66 网络编程(五)——TCP多线程实现多人聊天室
思路
- 客户端读写各一个类,可以使内部类,实现Runnable。读写类都与服务器端建立连接,一个收,一个发。
- 客户端实现接收和转发。多线程实现每个客户端的连接(使与各客户端的连接独立)。
- 服务器端中创建一个公共缓冲池,用于存放消息。通过服务器中的转发方法转发给个客户端。
客户端 代码
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(); } } } } //}
服务器端 代码
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();//转发完后清空 } } }
演示
服务器端运行一个,客户端运行多个。