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();//转发完后清空
			
		}
	}
}

  

演示

服务器端运行一个,客户端运行多个。

66 网络编程(五)——TCP多线程实现多人聊天室

上一篇:66. mysql 的主从设置


下一篇:Linux 编译boost_1_66_0.7z