zoukankan      html  css  js  c++  java
  • 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();//转发完后清空
    			
    		}
    	}
    }
    

      

    演示

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

  • 相关阅读:
    列表去重
    Python中操作SQLAlchemy,SQLAlchemy中文技术文档
    gunicorn部署Flask服务
    Asset Catalog Help (十一)---Removing Images and Sets
    Asset Catalog Help (十)---Specifying a Resizable Area of an Image
    Asset Catalog Help (九)---Changing Image Set Names
    Asset Catalog Help (八)---Customizing Image Sets for Devices
    Asset Catalog Help (七)---Customizing Image Sets for Size Classes
    Asset Catalog Help (六)---Adding OS X Icons
    Asset Catalog Help (五)---Migrating an iOS App Icon Set or Launch Image Set
  • 原文地址:https://www.cnblogs.com/Scorpicat/p/12067824.html
Copyright © 2011-2022 走看看