Java程序猿必学第二十三篇——网络编程(聊天室)与反射

Java程序猿必学第二十三篇——网络编程(聊天室)与反射

//1. 网络编程案例
//1.1 注册功能
//案例:注册功能
//分析:
//1.客户端与服务器建立连接
//2.客户端准备好注册数据,拼成一个字符串;例如:{id:"1001",name:"zs",age:30}
//3.发送注册数据,服务器接收数据
//4.服务器拆分数据,取出id对应的value作为key,接收的注册信息作为value
//5.判断key在配置文件中是否存在,如果存在,则返回"已存在"
//6.不存在,把这些数据存到配置文件,并返回“注册成功”
//-----服务器------
public class Server {
	public static void main(String[] args) throws IOException {
		ServerSocket ss = new ServerSocket(9527);
		Socket socket = ss.accept();
		InputStream is = socket.getInputStream();
		BufferedReader br = new BufferedReader(new InputStreamReader(is));
		String msg = br.readLine(); //{id:1001,name:zs,age:30}
		String strId = msg.split(",")[0];  //{id:1001
		String id = strId.split(":")[1];   //1001
		
		//通过Properties集合去加载配置文件
		Properties p = new Properties();
		p.load(new FileInputStream("user.properties"));
		
		OutputStream os = socket.getOutputStream();
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os));
		if(p.containsKey(id)) {
			bw.write("已存在");
			
		}else {
			Tool.saveProperties(id,msg);  //将数据存储到配置文件
			bw.write("注册成功");
		}
		bw.newLine();
		bw.flush();
		
		IOUtils.closeAll(bw,os,br,is,socket);
		
	}
}



//-----客户端------
public class Client {
	public static void main(String[] args) throws IOException {
		Socket socket = new Socket("127.0.0.1",9527);
		OutputStream os = socket.getOutputStream();
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os));
		
		String json = getData(); //{id:1001,name:zs,age:30}
		//发数据
		bw.write(json);
		bw.newLine();
		bw.flush();
		
		InputStream is = socket.getInputStream();
		BufferedReader br = new BufferedReader(new InputStreamReader(is));
		String msg = br.readLine();
		System.out.println("服务器响应:"+msg);
		
		IOUtils.closeAll(is,br,os,bw,socket);
	}

	private static String getData() {
		Scanner sc = new Scanner(System.in);
		System.out.println("请输入ID:");
		String id = sc.next();
		System.out.println("请输入用户名:");
		String name = sc.next();
		System.out.println("请输入年龄:");
		int age = sc.nextInt();
		return "{id:"+id+",name:"+name+",age:"+age+"}";
	}
}


//----工具类----
public class Tool {
	public static void saveProperties(String id, String msg) throws FileNotFoundException, IOException {
		Properties properties = new Properties();
		properties.put(id, msg);
		properties.store(new FileOutputStream("user.properties"), "");
	}
}


//1.2 聊天室程序
//案例:聊天室程序
//分析: 多人聊天---多线程
//1.通过多线程形式接收多个客户端的连接
//2.客户端要录入姓名,传入服务器接收,并存储到线程中
//(注意:客户端的发送和接收要分为两个线程,才能方便群发)
//3.服务器给客户端回应“欢迎进入聊天室”
//4.该客户端就可以实时发数据聊天了
//5.要实现服务器群发信息给客户端,需要先将所有线程对象存储
//6.退出方式,客户端退出,其他用户应该都知道
 

-------服务器-------
public class Server {
	public static List<ServerThread> list = new ArrayList<ServerThread>();
	public static void main(String[] args) throws IOException {
		ServerSocket ss = new ServerSocket(9527);
		//多线程方式监听及创建socket
		while(true) {
			Socket socket = ss.accept();
			System.out.println("有一个客户端进来了");
			ServerThread st = new ServerThread(socket);
			st.start();
			list.add(st);  //存储线程对象
		}
	}
}


//------服务器线程-------
public class ServerThread extends Thread {
	private Socket socket;
	
	private BufferedReader br;
	private BufferedWriter bw;
	
	public ServerThread(Socket socket) throws IOException {
		this.socket = socket;
		br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
		bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
	}
	
	@Override
	public void run() {
	
		try {
			sendHello();  //欢迎
			
			while(true){
				String name = this.br.readLine(); //读取到数据后,发给自身
				String msg = this.getName()+"说:"+name;
				//循环遍历线程对象,除了自己,都发一份出去
				for(ServerThread st : Server.list) {
					if(st!=this) {
						st.bw.write(msg);
						st.bw.newLine();
						st.bw.flush();
					}
				}
			}
		} catch (Exception e) {
			String msg = this.getName()+"退出了聊天室";  //群发退出信息
			Server.list.remove(this);  //将当前线程对象在集合中移除
			
			for(ServerThread st : Server.list) { //移除后群发
				try {
					st.bw.write(msg);
					st.bw.newLine();
					st.bw.flush();
				} catch (IOException e1) {
					e1.printStackTrace();
				}
			}
			
		}finally {
			IOUtils.closeAll(bw,br,socket);
		}
	}

	private void sendHello() throws IOException {
		String name = br.readLine(); //读取到数据后,发给自身
		String msg = "【温馨提示】:欢迎"+name+"进入聊天室";
		this.setName(name);  //记录客户的访问
		bw.write(msg);
		bw.newLine();
		bw.flush();
	}
}


//------客户端-------
public class Client {
	public static void main(String[] args) throws IOException {
		Socket socket = new Socket("127.0.0.1",9527);
		
		//客户端读写分离
		new WriteClient(socket).start();
		
		new ReadClient(socket).start();

	}
}



//-------客户端写线程-------
public class WriteClient extends Thread {
	private Socket socket;
	
	public WriteClient(Socket socket) {
		this.socket = socket;
	}
	
	@Override
	public void run() {
		OutputStream os = null;
		BufferedWriter bw = null;
		try {
			os = socket.getOutputStream();
			bw = new BufferedWriter(new OutputStreamWriter(os));
			System.out.println("请输入用户名:");
			Scanner sc = new Scanner(System.in);
			
			while(true) {
				String name = sc.next(); //第一次是输入名字,后面就是聊天内容
				bw.write(name);
				bw.newLine();
				bw.flush();
			}
			
		} catch (IOException e) {
			e.printStackTrace();
		}finally {
			IOUtils.closeAll(os,bw,socket);
		}
		
	}
}



//-------客户端读线程--------
public class ReadClient extends Thread {
	private Socket socket;
	
	public ReadClient(Socket socket) {
		this.socket = socket;
	}
	
	@Override
	public void run() {
		InputStream is = null;
		BufferedReader br = null;
		try {
			is = socket.getInputStream();
			br = new BufferedReader(new InputStreamReader(is));
			while(true) {
				String msg = br.readLine();
				System.out.println(msg);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}finally {
			IOUtils.closeAll(is,br,socket);
		}
		
	}
}



//2. 反射(重点)
//2.1 反射概述
/**
 *概述:反射对象,就是类对象,是类加载的产物,
     只要有了类对象,就可以知道类的所有信息(类名,接口,包名,属性,方法等)

	获取类对象方式:
	1.类名.class  (常用)  
	2.对象.getClass()   
	3.Clas.forname("包名.类名")  (常用)
	
	结论:无论哪种方式获取的类对象,都是同一个
 *
 */

class Person{
	private String name;
	private int    age;
	

	
	public Person() {
		System.out.println("调无参构造");
	}

	public Person(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}


	public void test() {
		System.out.println("test");
	}
	
	
}
public class Test1 {
	public static void main(String[] args) throws ClassNotFoundException {
		Class class1 = Person.class;
		Class class2 = new Person().getClass();
		Class class3 = Class.forName("com.qf.d_reflect.Person");
		
		System.out.println(class1==class2); //true
		System.out.println(class1==class3); //true
	}
}

//2.2 反射常用方法
public class Test2 {
	public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchFieldException, SecurityException, NoSuchMethodException {
		Class clazz1 = Person.class;  //获取反射对象
		
		System.out.println(clazz1.getName()); //获取类名
		System.out.println(clazz1.getPackage());  //获取包名
		System.out.println(clazz1.getSuperclass()); //获取父类
		System.out.println(Arrays.toString(clazz1.getInterfaces())); //获取接口
		System.out.println(Arrays.toString(clazz1.getFields())); //性能高,不能处理私有权限属性
		System.out.println(Arrays.toString(clazz1.getDeclaredFields())); //(常用)可以处理私有权限
		System.out.println(Arrays.toString(clazz1.getMethods()));//(常用)
		System.out.println(Arrays.toString(clazz1.getConstructors())); //获取所有构造器
		System.out.println(clazz1.getDeclaredField("name"));  //(常用) 获取Field对象
		System.out.println(clazz1.getMethod("test"));  //(常用) 获取Method对象 
		System.out.println(clazz1.newInstance()); //调无参构造 (常用)
	}
}


//2.3 反射操作属性
//通过反射对象,给私有属性赋值及取值
//分析:
//1.获取反射对象
//2.获取Field对象
//3.调用set方法赋值 ,通过get方法取值
class Student{
	private String name;
	private int    age;
	
	public String getName() {
		return name;
	}
	
	public void hello(String name,int age) {
		System.out.println("反射的方法调用--"+name+"--"+age);
	}
}
public class Test1 {
	public static void main(String[] args) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException, InstantiationException {
		Class clazz = Student.class;
		Field field = clazz.getDeclaredField("name");
		field.setAccessible(true);  //开启私有权限
		Student st = (Student) clazz.newInstance();
		field.set(st, "zsf");
		
		System.out.println(field.get(st));
		System.out.println(st.getName());  //验证value值是否存储到name属性
		
	}
}



//2.4 反射操作方法
//案例2:通过反射对象调用方法
//1.获取反射对象
//2.通过反射获取Method对象,传方法名和反射类型
//3.通过Method对象调invoke方法

//反射作用:可以灵活动态操作属性和方法
public class Test2 {
	public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException {
		Class<Student> class1 = Student.class;
		//获取Method对象,参数1:方法名    后面参数:参数类型反射对象
		Method method = class1.getMethod("hello", String.class,int.class);
		method.invoke(class1.newInstance(), "谭小虎",28);
	}
}



//2.5 反射应用场景
//案例3:通过反射对象灵活的获取老师和学生的对象
class Teacher{
}
public class Test3 {
	public static void main(String[] args) throws InstantiationException, IllegalAccessException {
		//常规获取对象方式:
		//弊端: 每次获取对象时,都创建了不同的方法
		Teacher teacher = Tool.getTeacher();
		Student student = Tool.getStudent();
		
		//使用反射灵活获取对象
		Teacher t1 = Tool.getObject(Teacher.class);
		Student s1 = Tool.getObject(Student.class);
		System.out.println(t1+"---"+s1);
		
	}
}

//----工具类调用-----
public class Tool {
	public static Teacher getTeacher() {
		return new Teacher();
	}

	public static Student getStudent() {
		return new Student();
	}

	//泛型方法
	public static <T> T getObject(Class<T> class1) throws InstantiationException, IllegalAccessException {
		return class1.newInstance();
	}
}
上一篇:用lilypond自带案例编命令:给一列音加Staccato


下一篇:IDEA 自动导包设置