第六周笔记

文章详细介绍了Java中的TCP编程,包括客户端和服务器的通信流程,TCP的三次握手过程。同时,展示了客户端上传图片文件至服务器的案例。此外,还探讨了Java的序列化和反序列化概念,以及如何使用ObjectInputStream和ObjectOutputStream。最后,文章讲解了反射的基本用法,如获取构造器、属性和方法,并介绍了JDK动态代理的原理和InvocationHandler的使用。
摘要由CSDN通过智能技术生成

网络编程

一、TCP编程

1.TCP客户端和服务器的通信流程

客户端:Socket s = new Socket("IP地址",端口号)
	客户端将数据写入通道内  OutputStream out = s.getOutputStram()
		一次写入一个字节数组,发送给服务器端
	客户端获取通道内的字节流 InputStream is = s.getInputStream()
		一次读取一个字节数组,展示客户端的反馈信息
服务器端:ServerSocket ss = new ServerSocket(端口号)
	监听客户端连接   Socket s = ss.accept();
	获取监听到指定客户端的通道内的字节输入流对象 InputStream in = s.getInputStream()
		一次读取一个字节数组--->获取对象
	服务器在获取监听到客户端通道内的字节输出流对象,反馈给客户端消息 
		OutputStream out = s.getOutputStream()

2.TCP的三次握手

SYN:同步序列编号
ACK:应答机制(消息确认符-->表示数据已经准确接收无误
	客户端给服务器发送一个握手信号SYN
	服务器端反馈给客户端SYN+ACK:数据已经收到
	客户端反馈给服务器SYN+ACK:客户端数据已收到,反馈给服务器端
	当这些结束之后,客户端和服务器建立通信。

3.客户端

创建TCP协议这种方式的客户端的socket对象
	java.net.Socket -->public Socket(String host,int port)

4.服务器端

创建服务器端的Socket对象-->绑定端口
	public ServerSocket(int port)throws IOException

5.案例

​ 需求:客户端上传图片文件—>读取当前项目xxx.jpg图片文件—写给服务器‘

服务器端读取传过来的xx.jpg图片文件—复制到指定磁盘上的 copy.jpg文件中,服务器端加入反馈(反馈客户端)!

public class Client {
    public static void main(String[] args) throws IOException {
        //创建客户端的Socket
        Socket s = new Socket("10.35.165.17",2222) ;
        //创建字节缓冲输入流
        BufferedInputStream bis = new BufferedInputStream(
                new FileInputStream("bug2.jpg")) ;
        //获取通道内的字节输出流,----封装字节缓冲输出流
        BufferedOutputStream bos  = new BufferedOutputStream(s.getOutputStream()) ;
        //一次读取一个字节数组
        byte[] bytes = new byte[1024] ;
        int len = 0 ;
        while((len=bis.read(bytes))!=-1){
            //给通道内的输出流写数据
            bos.write(bytes,0,len) ;
            //刷新
            bos.flush();
        }
        //告知服务器端,没有流数据写过去
        s.shutdownOutput();
        //读取反馈
        //获取客户端通道内的字节输入流
        InputStream inputStream = s.getInputStream();
        //一次读取一个字节数组
        byte[] buffer = new byte[1024] ;
        int length = inputStream.read(buffer);
        String str = new String(buffer,0,length) ;
        System.out.println("str:"+str) ;
        //释放资源
        bis.close();
        s.close();
        //关闭资源
    }
}
public class Server {
    public static void main(String[] args) throws IOException {
        //服务器端的Socket
        ServerSocket ss = new ServerSocket(2222) ;
        //监听客户端连接
        Socket s = ss.accept()  ;
        //获取通道内字节输出流---->封装字节缓冲输入流
        BufferedInputStream bis = new BufferedInputStream(s.getInputStream()) ;
        //创建字节缓冲输出流---写数据到指定文件中
        BufferedOutputStream bos = new BufferedOutputStream(
                new FileOutputStream("D:\\EE_2302\\day29\\code\\my.jpg")) ;
        //一次读取一个字节数组
        byte[] bytes  = new byte[1024] ;
        int len = 0 ;
        while((len=bis.read(bytes))!=-1){
            bos.write(bytes,0,len);
            //刷新
            bos.flush();
        }
        //服务器加入反馈
        //获取通道内字节输出流
        OutputStream outputStream = s.getOutputStream();
        outputStream.write("图片上传完毕".getBytes()) ;
        //释放资源
        bos.close();
        ss.close();
    }
}

序列化

序列化:就是使用ObjectOutputStream将一个Java对象的信息写入流中
             对象--->数据流(流数据)
	构造方法:public ObjectOutputStream(OutputStream out)
	成员方法:public final void writeObject(Object obj) 将指定的对象写入到序列化流中,变成流数据
	
反系列化:就是使用ObjectInputStream 将数据流中的内容--->还原成--->对象
	构造方法:
	     public ObjectInputStream(InputStream in)
	成员方法:
	     public final Object readObject():从反序列流中将数据流的内容----解析成对象

举例

//反序列化
public static void read() throws IOException, ClassNotFoundException {
      //创建反序列化流对象ObjectInputStream
      ObjectInputStream ois = new ObjectInputStream(new FileInputStream("oos.txt")) ;

      // public final Object readObject():从反序列流中将数据流的内容----解析成对象
      Object object = ois.readObject();
      //强转学生类型
      Student s = (Student) object;
      System.out.println(s.getName()+"---"+s.getAge());
    }
//序列化
public static void write() throws IOException {
      //创建序列化流对象
      ObjectOutputStream oos = new ObjectOutputStream(new 										FileOutputStream("oos.txt")) ;
      //public final void writeObject(Object obj) :将指定的对象写入到序列化流中,变成流数据
      //创建一个学生对象
      Student s = new Student("高圆圆",44) ;
      oos.writeObject(s) ;
      //java.io.NotSerializableException: com.qf.io_01.Student  当前这个类未实现序列化异常

    }

反射

1.什么是反射

什么是反射? (jvm正在编译的时候,就可以获取这个类所有的信息!)
	 (Reflection),一个类在加载运行状态的时候,可以动态获取正在运行的类(Class)
	创建正在运行类的对象(构造器-Constructor)
	使用正在运行的这个类的对象去给 成员变量赋值(Field)
	调用正在运行的这个类中成员方法(Method)
	
反射应用----Java设计模式
正射 ----就是我们自己书写的代码的时候, 类名 对象名 =  new 类名() ;

2.获取字节码文件的方式

	1)调用Object类的getClass方法
	2)任意Java类型的class属性

	3)第三种方式:(推荐)
		Java提供类Class:表示正在运行的Java应用程序中的类和接口
		有一个静态方法:
	          参数:类的完全限定名称。 (包名.类名) String类型:经常用在配置文件中xx.properties
	             public static Class<?> forName(String className):

3.获取构造器的Constructor对象并创建实例

1)获取指定公共的构造方法的Constructor对象
	public Constructor<T> getConstructor(Class<?>... parameterTypes)
	获取指定的公共的构造方法的Constructor对象,参数:指定参数类型的Class类对象,如果没有参数,可以不写
		举例:String类型的参数---java.lang.String
		int---->java.lang.Integer
2)获取所有的指定有参构造构造方法的Constructor对象
	public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
    参数是:当前参数类型的字节码文件 String--->String.class
3)创建当前类实例  
    public T newInstance(Object... initargs)
    参数:通过构造器里面给当前正在运行的类的成员变量赋值:实际参数
    返回T---Type:代表任意Java对象
4)当设置非公共属性时应当设置取消java语言访问检查
	public void setAccessible(boolean flag) 
	参数为true:取消Java语言访问检查

4.通过Class字节码文件对象获取属性(成员变量)/设置值

1)获取所有的公共字段(成员变量)
	public Field[] getFields()
2)获取"这个类"所有的字段所在的Field类对象,公共的/默认的/私有的/受保护的
	public Field[] getDeclaredFields()
    public Fileld[] getDeclaredFields(String name) 
    	参数为:这个类的属性名称
3)将指定的value实际参数作用在指定的当前类的实例上--->为字段赋值
	public void set(Object obj,Object value)

5.获取成员方法/调用方法

1)获取这个类的所有的公共的成员方法的类对象Method(包括继承过来的以及实现接口的方法)
	public Methods[] getMethods()
2)获取类所有的的指定的成员方法的类对象Method,不包括继承过来的
	public Methods[] getDeclaredMethods()
3)获取指定的公共成员方法
    public Method getMethod(String name,Class<?>... parameterTypes)
    	参数1:方法的名称
    	参数2:当前方法中参数类型的Class
4)获取指定的成员方法所在的类对象Method
    public Method getDeclaredMethod(String name,Class<?>... parameterTypes)
    	参数1:方法的名称
    	参数2:当前方法中参数类型的Class
5)调用方法
	public Object invoke(Object obj,Object... args)
        参数1:这个类的实例
        参数2:方法中传入的实际参数

JDK动态代理

1.代理思想/静态代理

代理设计模式---属于"结构型设计模式"
代理核心思想:代理角色帮助真实角色对他的业务功能进行增强!
	静态代理
	   特点:代理角色和真实角色必须实现同一个接口!
	   弊端:业务功能和增强的功能没有完全分离!

2.动态代理

jdk动态代理--->jdk提供的
         java.lang.reflect.Proxy:动态代理类
     1)静态方法:
         public static Object newProxyInstance(
             ClassLoader loader, //获取接口实例的类加载器
             Class<?>[] interfaces,//实现的接口列表的字节码文件(代理类要的实现接口列表的Class)
		 	 InvocationHandler h)//有代理实例调用 接口方法的处理程序:接口类型 
		 								抛出异常 throws IllegalArgumentException
      2)InvocationHandler:接口
      	 public Object invoke(Object proxy, Method method, Object[] args)
             参数1:调用该方法的代理实例
             参数2:调用该代理实例的接口方法的Method类对象
             参数3:调用接口方法中所有的参数,组成数组,没有参数,可不写

举例

//测试类中
UserDao ud = new UserDaoImple() //真实角色
InvocationHandler handler = new MyInvocationHandler(ud) ;
UserDao ud3 = (UserDao) Proxy.newProxyInstance(
           ud.getClass().getClassLoader(),//代理实例要实现的接口的字节码文件---类加载
           //代理实例要实现接口列表的Class--->Class类中--public 类<?>[] getInterfaces()
           ud.getClass().getInterfaces(),
           //代理实例调用接口方法的处理程序
           handler);
ud3.add() ;
//InvocationHandler接口类
/*
* @param proxy  调用该方法的代理实例
* @param method 调用该代理实例的接口方法的Method类对象
* @param args 调用接口方法中所有的参数,组成数组,没有参数,可不写
* @return 从代理实例上的方法调用返回的值
* @throws Throwable 可能调用方法失败!
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable {
    System.out.println("操作业务功能之前,先权限校验!" );
    //反射的写法调用接口方法--add()/delete()/udate()/findAll()
    Object obj = method.invoke(target, args);
    System.out.println("操作业务功能之后,产生日志记录!");
    return obj; //方法的返回值
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值