群聊聊天室

群聊聊天室


改进好多线程聊天室,虽然一定程度上实现了多个用户的聊天进行,但是所有的聊天信息都是显示在服务端的,而这是不显示的。
改进代码,使用户可以在自己的客户端看到自己及其他的用户信息。

服务端

package com.tedu.socket;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Arrays;

/**
 * 聊天室服务器端
 * @author Wildmess
 *
 */
public class Server {

	/*
	 * java.net.ServerSocket
	 * 服务器端运行这个类的对象
	 * 1.申请服务端口
	 * 2.能够监听客户端发送过来的信息
	 */
	private ServerSocket server;

	/*
	 * 定义一个输出流数组,保存的是指定各个客户端的输出流
	 */
	private PrintWriter[] allout = {};

	public Server() {
		try {
			/*
			 * 实例化ServerSocket对象
			 * 向操作系统申请端口
			 * 如果这个端口被占用就会发生异常
			 */
			System.out.println("服务器正在启动……");
			server = new ServerSocket(8088);
			InetAddress ip = InetAddress.getLocalHost();
			System.out.println("服务器"+ ip +"启动完毕");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public void start() {
		/*
		 * 返回值使用一个Socket
		 * server.accept()
		 * 这个方法是一个阻塞方法,调用后,程序暂停等待客户端的信息发送过来
		 * 没有信息过来就一直等
		 */
		try {

			System.out.println("等待客户端连接……");

			while(true) {
				Socket socket = server.accept();//等价于正常情况下的Scanner
				System.out.println("第" + (allout.length+1) + "个新的客户端连接了……");

				/*
				 * 将每一个客户端用于输出、输入的流等操作做成一个单独的线程
				 */
				ServerThread serverThread = new ServerThread(socket);
				Thread t = new Thread(serverThread);
				t.start();			
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	public static void main(String[] args) {
		Server server = new Server();
		server.start();
	}

	class ServerThread implements Runnable{
		//客户端发送过来的socket名称及地址信息
		private Socket socket;
		private String ip;

		public ServerThread(Socket socket) {
			this.socket = socket;
			this.ip = socket.getInetAddress().getHostAddress();
		}

		public void run() {
			PrintWriter pw = null;
			try {
				//从socket中获取输入流
				InputStream is = socket.getInputStream();
				InputStreamReader isr = new InputStreamReader(is,"utf-8");
				BufferedReader br = new BufferedReader(isr);
				
				//获得要发送到客户端信息的输出流
				OutputStream os = socket.getOutputStream();
				OutputStreamWriter osw = new OutputStreamWriter(os,"utf-8");
				BufferedWriter bw = new BufferedWriter(osw);
				pw = new PrintWriter(bw,true);
				
				synchronized (allout) {
					/*
					 * 这个代码是有新客户端连接时运行一次的
					 * 目的是将pw放入输出流数组中
					 */
					//1.数组扩容
					allout = Arrays.copyOf(allout, allout.length+1);
					//将当前获得的输出流放入到数组中
					allout[allout.length-1] = pw;
					System.out.println("[" + ip + "]" + "上线了,当前还有" + allout.length + "人");
				}

				String line=null;
				while((line = br.readLine())!=null) {
					//System.out.println("[" + count + "]" + ip + ":" +line);
					synchronized (allout) {
						for (int i = 0; i < allout.length; i++) {
							allout[i].println("[" + ip  + "]" + ":" +line);
						}
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
			} finally{
				//客户端断开后的操作
				//将当前要断开的客户端的输出流从数组中删除
				synchronized (allout) {
					for (int i = 0; i < allout.length; i++) {
						if(allout[i] == pw) {
							allout[i] = allout[allout.length-1];
							allout = Arrays.copyOf(allout, allout.length-1);
							System.out.println("[" + ip + "]" + "下线了,当前还有" + allout.length + "人");
						}
					}
				}
	
				try {
					socket.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
}

客户端

package com.tedu.socket;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.util.Scanner;

public class Client {
	/*
	 * java.net.socket
	 * Socket封装了TCP通信细节,我们只需要明确IP地址和端口号
	 * 像服务器端发送输出流(输入流)即可
	 */
	private Socket socket;

	public Client() {

		try {
			/*
			 * 实例化Socket需要俩个参数
			 * 1.服务器服务端IP地址
			 * 2.服务器端,端口号
			 * 
			 * 只要实例化成功就是连接成功
			 * 如果连接失败就会出现异常
			 * 
			 */
			System.out.println("正在连接服务器……");
			//socket = new Socket("localhost", 8088);
			socket = new Socket("172.117.55.169",8088);
			System.out.println("已连接服务器……");
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	/**
	 * 具体控制客户端说话的方法
	 */

	public void start() {
		/*
		 * 启动接受服务端消息的线程
		 */
		ClientServerThread clientServerThread = new ClientServerThread();
		Thread t = new Thread(clientServerThread);
		t.start();
		
		/*
		 * 发送信息,需要输出流
		 * 输出到服务端
		 */
		try {
			OutputStream os = socket.getOutputStream();
			OutputStreamWriter osw = new OutputStreamWriter(os,"utf-8");
			BufferedWriter bw = new BufferedWriter(osw);
			PrintWriter pw = new PrintWriter(bw,true);

			Scanner sc = new Scanner(System.in);
			while(true) {
				String line = sc.nextLine();
				pw.println(line);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void main(String[] args) {
		Client client = new Client();
		client.start();
	}
	
	/**
	 * 用于创建接受服务端信息的线程
	 * @author Wildmess
	 *
	 */
	class ClientServerThread implements Runnable{
		public void run() {
			try {
				InputStream is = socket.getInputStream();
				InputStreamReader isr = new InputStreamReader(is,"utf-8");
				BufferedReader br = new BufferedReader(isr);
				
				String line = null;
				while((line = br.readLine())!=null) {
					System.out.println(line);
				}
				
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}```

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值