UDP多线程聊天室:
Runable接口的方式
发送端的线程
public class SendThread implements Runnable {
private DatagramSocket ds=null;
public SendThread(DatagramSocket ds) {
super();
this.ds = ds;
}
@Override
public void run() {
// TODO 自动生成的方法存根
try {
while(true) {
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
String line=null;
while((line=br.readLine())!=null) {
if("886".equals(line)) {
break;
}
byte[] bs = line.getBytes();
DatagramPacket dp=new DatagramPacket(bs, 0, bs.length, InetAddress.getByName("172.21.195.19"), 10086);
ds.send(dp);
}
ds.close();
}
} catch (Exception e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
}
接收端的线程
public class ReceiveDemo implements Runnable{
private DatagramSocket ds=null;
public ReceiveDemo(DatagramSocket ds) {
super();
this.ds = ds;
}
@Override
public void run() {
// TODO 自动生成的方法存根
while(true) {
byte [] by=new byte[1024];
int len=by.length;
DatagramPacket dp=new DatagramPacket(by, len);
try {
ds.receive(dp);
String ip=dp.getAddress().getHostAddress();
String data=new String(dp.getData(), 0, dp.getLength());
System.out.println("ip:"+ip+"\n"+"data:"+data);
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
}
}
主线程
只需要需一个窗口 ,让我们不断发送数据
public static void main(String[] args) throws Exception {
DatagramSocket ds=new DatagramSocket();
DatagramSocket dss=new DatagramSocket(10086);
SendThread st=new SendThread(ds);
ReceiveDemo rd=new ReceiveDemo(dss);
Thread t1=new Thread(rd);
Thread t2=new Thread(st);
t1.start();
t2.start();
}
TCP ( 建立连接通道) 编程
客户端的开发步骤
1)创建客户端的Socket对象
Socket:就是客户端的Socket
构造方法
public Socket(InetAddress address, int port)
public Socket(String host, int port):创建客户端套接字对象,并且指定端口号和ip文本形式
2)获取通道内的输出流对象
3)给服务器端写数据
4)释放资源
java.net.ConnectException: Connection refused: connect 连接被拒绝
不要先运行客户端,客户端的连接需要服务器监听到才能连接
服务端的开发步骤:
1)创建服务器端的Socket对象
2)监听客户端的连接(阻塞方法)
3)获取通道内的输入流
4)读取数据,显示控制台
5)释放资源
java.net.BindException: Address already in use: JVM_Bind 地址被绑定,因为已经有服务器在监听客户端连接
客户端读取当前项目下的某个文本文件,服务器复制这个文件内容输出一个新的文本文件(Copy.java)
解决等待反馈的方案:
1)客户端这边,写一个结束条件,---->服务器如果读取到了这个结束条件的话,服务器就可以反馈
第一种方式虽然可以解决这种问题,不好,不灵活!
2)public void shutdownOutput():通知服务器端(我没有数据了,你赶紧反馈)
客户端将文本文件中的数据,复制到服务器端输出的新的java文件中,然后服务器端要给客户端反馈数据,客户端将反馈的数据展示
客户端:
public static void main(String[] args) throws Exception {
Socket s=new Socket("172.21.195.19", 10086);
BufferedReader br=new BufferedReader(new FileReader("ServerSocketDemo.java"));
BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
String line=null;
while((line=br.readLine())!=null) {
bw.write(line);
bw.newLine();
bw.flush();
}
s.shutdownOutput();
InputStream in = s.getInputStream();
byte[] by=new byte[1024];
int len = in.read(by, 0, by.length);
System.err.println(new String (by,0,len));
s.close();
br.close();
}
服务端:
public static void main(String[] args) throws Exception {
ServerSocket ss=new ServerSocket(10086);
Socket s = ss.accept();
BufferedWriter bw=new BufferedWriter(new FileWriter("Copy.java"));
BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream()));
String line=null;
while((line=br.readLine())!=null) {
bw.write(line);
bw.newLine();
bw.flush();
}
OutputStream out = s.getOutputStream();
byte[] by = "复制成功!!!".getBytes();
out.write(by, 0, by.length);
out.flush();
s.close();
bw.close();
}
反射
什么是反射:
反射就是通过获取class字节码文件对象/Class的类对象,获取该字节码文件对象中的成员变量,构造方法,和成员方法
Field: 简称成员变量 (Field 提供有关类或接口的单个字段的信息,以及对它的动态访问权限。
反射的字段可能是一个类(静态)字段或实例字段。
Constructor:简称构造方法:提供关于类的单个构造方法的信息以及对它的访问权限。
Method:简称成员方法:类或接口上单独某个方法(以及如何访问该方法)的信息
如何获取class字节码文件对象/Class的类对象
三种方式来获取这个class字节码文件对象:
1)Object中的getClass()
2)任何数据类型的静态属性class
3)Class类中的方法:
forName(String className)
开发中使用第三种方式,forName方法中的参数是一个String类型,以后可以用字符串类型数据作为配置文件!forName("类路径")
通过字节码文件对象获取构造方法并使用.
创建Person对象
Person p = new Person() ;
System.out.println(p) ;
1) 先获取Person类的字节码文件对象
2)public Constructor<?>[] getConstructors()
Class 对象所表示的类的所有公共构造方法
public Constructor<?>[] getDeclaredConstructors():获取当前字节码文件对象中的所有的构造方法
Class c=Class.forName("反射的三种实现方式.Person");
// 获取所有的共有构造函数
// Constructor[] cons = c.getConstructors();
// 获取所有的构造函数
Constructor[] cons = c.getDeclaredConstructors();
for(Constructor c1:cons) {
System.out.println(c1);
}
2)获取单个构造方法(公共的,带三个参数的)
public Constructor<T> getConstructor(Class<?>... parameterTypes)
3)创建构造方法表示的该类的实例对象
Object obj = con.newInstance("高圆圆",27,"户县") ;
public void setAccessible(boolean flag)
值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查
public static void main(String[] args) throws Exception {
Class c=Class.forName("反射的三种实现方式.Person");
// 获取公共的无惨构造函数
Constructor cons= c.getConstructor();
System.out.println(cons);
System.out.println("-------------------");
// 获取指定的公共构造函数
Constructor cc=c.getConstructor(String.class,int.class,String.class);
System.out.println(cc);
System.out.println("-------------------");
// 获取私有的构造函数
Constructor c2=c.getDeclaredConstructor(String.class);
// 创建该类的对象
// 取消访问检查
c2.setAccessible(true);
Object obj = c2.newInstance("gao");
System.out.println(c2);
System.out.println(obj);
System.out.println("-------------------");
}
获取当前字节码文件对象中的所有的公共的成员变量
public Field[] getDeclaredFields():获取当前字节码文件对象中所有的字段
public Field[] getFields()
public void set(Object obj,Object value)
参数1:表示给哪个对象设置当前字段的值
参数2:表示给当前获取的哪个Field对象的字段设置一个新的值
Class c=Class.forName("反射的三种实现方式.Person");
// 获取所有共有的字段
Field[] f1 = c.getFields();
for(Field f:f1) {
System.out.println(f);
}
System.out.println("---------------");
// 获取所有的字段
Field[] f2 = c.getDeclaredFields();
for(Field ff:f2) {
System.out.println(ff);
}
System.out.println("----------------");
// 给共有的字段赋值
Constructor con=c.getConstructor();
Object obj = con.newInstance();
Field f3 = c.getField("address");
f3.set(obj, "北京");
System.out.println(obj);
System.out.println(f3);
System.out.println("-----------------");
// 给私有的字段赋值
Field f4 = c.getDeclaredField("name");
f4.setAccessible(true);
f4.set(obj, "高圆圆");
System.out.println(obj);
System.out.println(f4);
System.out.println("-----------------");
}
获取当前字节码文件对象中的所有的公共的成员方法(包括父类中的)
public Method[] getMethods()
public Method[] getDeclaredMethods():所有的成员方法
获取单个的成员方法,Method
public Method getMethod(String name, Class<?>... parameterTypes)
参数1: 表示方法名
参数2:表示当前方法的参数数据类型的静态class属性
public Object invoke(Object obj, Object... args)
参数1:指定的哪个对象上调用底层invoke(),
参数2:表示的调用那个方法所传递的实际参数
public static void main(String[] args) throws Exception {
Class c=Class.forName("反射的三种实现方式.Person");
// 获取所有方法
Method[] m1 = c.getDeclaredMethods();
for (Method m : m1) {
System.out.println(m);
}
System.out.println("-----------------");
// 创建对象
Constructor con=c.getConstructor();
Object obj = con.newInstance();
// 调用共有无参方法
Method m2 = c.getMethod("show");
m2.invoke(obj);
System.out.println("-----------------");
// 调用共有有参
Method m3=c.getMethod("getString", String.class,int.class);
System.out.println(m3.invoke(obj,"高圆圆",100));
System.out.println("-----------------");
// 调用私有无参
Method m4=c.getDeclaredMethod("function");
m4.setAccessible(true);
m4.invoke(obj);
}
代理: 在程序的执行过程中,通过一个类Proxy和接口invacationHandler(处理程序)实现动态代理
Proxy类中的方法创建动态代理类对象 public static Object newProxyInstance(ClassLoader
loader,Class<?>[] interfaces,InvocationHandler h) 最终会调用InvocationHandler的方法
InvocationHandler Object invoke(Object proxy,Method method,Object[] args)
参数1:loader:类加载器 public ClassLoader getClassLoader() 参数2:public Class<?>[]
getInterfaces()
public class MyInvacationHandler implements InvocationHandler {
//给哪个对象生成代理 (目标对象)
private Object target ;
public MyInvacationHandler(Object target) {
this.target = target ;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//实现代理的程序
System.out.println("权限校验");
Object obj = method.invoke(target, args) ;
System.out.println("日志记录");
return obj;//返回的就是代理对象
}
}
public static void main(String[] args) {
// 创建UserDao对象
UserDao ud = new UserDaoImpl();
ud.add();
ud.delete();
ud.update();
ud.find();
System.out.println("------------------");
// 针对UserDao对象ud给它生产一个代理对象
// 调用处理程序,接口实现类中产生代理
MyInvacationHandler handler = new MyInvacationHandler(ud);
UserDao ud2 = (UserDao) Proxy.newProxyInstance(ud.getClass().getClassLoader(), ud.getClass().getInterfaces(),
handler);
ud2.add();
ud2.delete();
ud2.update();
ud2.find();
}