第六周学习总结

文章涵盖了Java中的网络编程,讲解了TCP和UDP协议的使用,包括Socket编程实现数据传输。同时,深入讨论了反射的概念,如何通过反射创建对象、调用方法和设置字段值。还涉及到了数据库基础,如MySQL的DDL语句以及数据表的操作。最后,介绍了静态和动态代理,特别是JDK动态代理的实现。
摘要由CSDN通过智能技术生成

day29

晨写+回顾

# 回顾内容
​
## 1.网络编程(Socket编程)三要素
​
```markdown
IP地址
    A/B/C三类:私人地址 C类:前面三个网络号段,后面是主机号段
port端口号
    0-65535---里面0-1024 属于"保留端口号" 
    指定端口:1025-65535
协议规则:
    UDP协议/TCP协议 区别
    
1)是否是可靠连接
    UDP:不可靠连接(不建立通道)
    TCP:是一种可靠连接(建立通道)
2)是线程安全
    UDP:不同步,执行效率高,线程不安全
    TCP:同步,执行效率低,线程安全!
3)是否传输数据大小有限制
    UDP--->有限制  "数据报包"的方式  DatagramPacket
    TCP--->无限制  以"字节流"的方式   客户端写数据---服务器端---读数据--->反馈客户端
    
```
​
## 2.UDP发送端和接收端的代码实现
​
### UDP发送端
​
```java
//1)创建发送端的Socket对象
DatagramSocket ds = new DatagramSocket() ;
//2)创建数据报包对象:包含的数据,数据的长度,ip地址对象,端口号
byte[] bytes = "hello,UDP我来了".getBytes() ;
DatagramPacket dp = new DatagramPacket(
        bytes,
    bytes.length,
    InetAddress.getByName("10.35.165.17"),
    10000) ;
//3)发送数据
ds.send(dp) ;
​
//4)释放资源
ds.close() ;
```
​
### UDP接收端
​
```java
//1)创建服务器端的Socket对象
DatagramSocket ds = new DatagramSocket(10000) ;
//2)创建一个"接收容器"(数据报包--->自定义字节缓冲区)
byte[] buffer = new byte[1024] ;
DatagramPacket dp = new DatagramPacket(buffer,buffer.length) ;
//3)使用"接收容器" 来接收数据
ds.receive(dp) ;
//4)解析数据
//获取实际的字节数组
byte[] bytes = dp.getData() ;
//获取实际的字节数长度
int length = dp.getLength() ;
//获取发送端的ip地址
String ip = dp.getAddress().getHostAddress() ;
//5)展示数据
String message = new String(bytes,0,length) ;
System.out.println("data from --->"+ip+",数据是:"+message) ;
//6)接收端一直开启,不关闭
​
```
​
## 3.一个窗口里面进行数据发送和接收(不断发送/不断接收并展示)
​
```
使用到了多线程的方式:发送端建立发送的资源类---使用线程进行操作 
                 接收端建立接收端的资源类-->使用线程Thread进行操作
```
​
------
​
------
​
## 今日内容
​
## 1.TCP方式来发送和接收数据
​
## 2.TCP方式的原理----三次握手(底层 sync(同步序列编号+ACK:消息确认字符)-三次握手)
​
## 3.TCP方式:客户端不断发送数据/服务器端不断接收并展示数据
​
## 4.TCP客户端读取文本文件--->传输服务器端,复制一个文本文件到指定目录
​
## 5.客户端图片文件(读--写给服务器)---服务器端接收图片(接收读,复制到指定磁盘上:写)
​
## 6.网络聊天
​
```
两个工程---->服务器端Server
            客户端:Client
    第一版:客户端不断发消息,服务器端不断接收,并回复消息  ,客户端读取消息     
    第二版:第一版问题:
                消息可能会出现阻塞---->多线程 
                                        使用继承Thread类--->重写run()
                                                        在子线程中:一般"读消息"
                客户端的读(读服务器的反馈)/服务器端的读(读客户端发送的消息)----->分别开启子线                        
                                    
```
​
### 作业:使用IO流模拟用户登录/注册
​
## 考试题
​
​
​
​
​
​
​
```
C:\Windows\System32\drivers\etc--->hosts文件
​
记录域名和他的ip地址
localhost   127.0.0.1---回环地址(代表本地)
```
​
​

TCP方式来发送和接收数据

package com.qf.tcp_01;
​
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
​
/**
 * TCP方式来发送和接收数据
 *
 * 1)创建TCP协议这种方式的客户端的socket对象
 * 2)写数据---写给服务器
 * 3)关闭资源
 */
public class TCPClient {
    public static void main(String[] args) throws IOException {
        //1)创建TCP协议这种方式的客户端的socket对象
        //java.net.Socket -->public Socket(String host,int port)
        Socket socket = new Socket("10.35.165.17",6666) ;
​
        //2)写数据---写给服务器
        //获取客户端通道内的输出流对象,写数据
        //public OutputStream getOutputStream()
        OutputStream out = socket.getOutputStream() ;
        out.write("hello,TCP我来了".getBytes());
​
        //3)释放资源
        socket.close();
​
    }
}
package com.qf.tcp_01;
​
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
​
/**
 * TCP服务器端
 *  1)创建服务器端的Socket对象-->绑定端口
 *  2)服务器端监听客户端连接--->获取到指定客户端的Socket对象
 *  3)获取通道的内输入流--->读数据
 *  4)关闭服务器端的Socket对象
 */
public class TCPServer {
    public static void main(String[] args) throws IOException {
        //1)创建服务器端的Socket对象-->绑定端口
        //public ServerSocket(int port)throws IOException
        ServerSocket ss = new ServerSocket(6666) ;
        System.out.println("正在等待客户端连接......");
​
        //2)服务器端监听客户端连接--->获取到指定客户端的Socket对象
        //public Socket accept()throws IOException:
        Socket socket = ss.accept();
        System.out.println("客户端已连接...");
​
        //3)获取监听到当前客户端的通道的内输入流--->读数据
        //public InputStream getInputStream()throws IOException
        InputStream inputStream = socket.getInputStream();
        //一次读取一个字节数组
        byte[] bytes = new byte[1024] ;
        int len = inputStream.read(bytes);
​
        //4)展示数据
        String message = new String(bytes,0,len) ;
        //获取ip地址
        //public InetAddress getInetAddress()
        String ip = socket.getInetAddress().getHostAddress() ;
​
        System.out.println("data from is ---->"+ip+",data is--->"+message) ;
​
        //5)释放资源
        ss.close();
​
    }
}
​

客户端发送数据,服务器端接收数据,展示客户端发送的数据,并同时反馈客户端数据,客户端读取反馈的数据

package com.qf.tcp_02;
​
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
​
/**
 * 客户端发送数据,服务器端接收数据,展示客户端发送的数据,并同时反馈客户端数据,客户端读取反馈的数据
 */
public class TcpClient {
    public static void main(String[] args) throws IOException {
        //创建客户端的Coekt对象
        Socket s = new Socket("10.35.165.17",7777) ;
​
        //获取客户端通道内的输出流对象
        OutputStream out = s.getOutputStream() ;
​
        //写数据
        out.write("hello,TCPServler".getBytes());
​
​
        //读取服务器反馈的数据
        //获取客户端通道内的输入流对象
        InputStream in  = s.getInputStream();
        //一次读取一个字节数组
        byte[] bytes = new byte[1024] ;
        int len = in.read(bytes);
        //展示数据
        System.out.println("serverMessage:"+new String(bytes,0,len));
​
​
        //释放资源
        s.close() ;
    }
}
package com.qf.tcp_02;
​
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
​
/**
 *服务器端
 */
public class TcpServer {
    public static void main(String[] args) throws IOException {
        //创建服务器端的Socket对象
        ServerSocket ss = new ServerSocket(7777) ;
​
        //监听客户额连接
        Socket s = ss.accept();
        //获取通道内的输入流对象
        InputStream inputStream = s.getInputStream();
        //一次读取一个字节数组
        byte[] bytes = new byte[1024] ;
        int len = inputStream.read(bytes);
        String clientMessage = new String(bytes,0,len) ;
        //展示数据
        System.out.println("data from --->"+s.getInetAddress().getHostAddress()+
                ",内容是:"+clientMessage);
​
        //服务器端反馈给客户端
        //服务器端获取监听客户端所在通道内的输出流对象
        OutputStream out = s.getOutputStream();
        out.write("数据已接收到".getBytes()) ;
​
        //释放资源
        ss.close() ;
    }
}
​

TCP客户端不断的去发送消息,服务器端不断的去接收数据,展示数据(服务器端不关闭)

package com.qf.tcp_03;
​
import java.io.*;
import java.net.Socket;
​
/**
 * TCP客户端不断的去发送消息,服务器端不断的去接收数据,展示数据(服务器端不关闭)
 */
public class TCPClient {
​
    public static void main(String[] args) {
​
        BufferedReader br = null ;
        Socket s  = null ;
        try {
            //创建客户端的Socket
            s = new Socket("10.35.165.17",10086) ;
​
            //客户端不断键盘录入数据--->BufferedReader一次读取一行
            br = new BufferedReader(
                    new InputStreamReader(System.in)) ;
​
            //获取客户端所在的通道内的字节输出流----OutputStream-->封装成字符缓冲输出流
            OutputStream outputStream = s.getOutputStream();
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(outputStream)) ;
            //一次读取一行
            String line = null ;
            while((line=br.readLine())!=null){
​
                bw.write(line) ;//写一行,通过封装后的通道的字符输出流写进去
                bw.newLine() ; //换行
                bw.flush() ; //刷新
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(br!=null){
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(s!=null){
                try {
                    s.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
package com.qf.tcp_03;
​
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
​
/**
 *服务器端不断的去接收数据,展示数据(服务器端不关闭)
 */
public class TCPServer {
    public static void main(String[] args) {
        try {
            //创建服务器端的Socket对象
            ServerSocket ss = new ServerSocket(10086)  ;
            //监听客户端连接
            Socket s = ss.accept();
            //封装通道内的字节输入流
            BufferedReader br = new BufferedReader(
                    new InputStreamReader(s.getInputStream())) ;
            String line = null ;
            while((line=br.readLine())!=null){
                //服务器自定义结束条件
                if("886".equals(line)){
                    break ;
                }
                //展示数据
                System.out.println("数据来自于"+s.getInetAddress().getHostAddress()+"内容是:"+line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
​
    }
}
​

需求:客户端读取当前项目下的xx.java文件,写给服务器端,服务器端读取这个xx.java文件,将这个文件复制到D:\EE_2302\day29\code\copy.java文件中

package com.qf.tcp_05;
​
import java.io.*;
import java.net.Socket;
​
/**
 * 需求:
 *      客户端读取当前项目下的xx.java文件,写给服务器端,服务器端读取这个xx.java文件,将这个文件
 *      复制到D:\EE_2302\day29\code\copy.java文件中
 * 分析:
 *      客户端---读取xx.java文件----->BufferedReader--->一次读取一行
 *          获取客户端通道字节输出流--->BuffferedWriter-->写一行/换行/刷新
 *
 *      服务器---->读取客户端写过来的数据--->监听到指定客户端,获取客户端所在的通道内的字节输入流--->
 *                      BufferedReader:一次读取一行
 *                      创建一个字符缓冲输出流:BufferedWriter---->一次写一行/换行/刷新--->
 *                                              输出到D:\EE_2302\day29\code\copy.java
 *
 *
 * 附件条件:
 *      客户端上传这个文本文件,服务器端复制完毕之后,加入反馈---客户端 "该文本文件已经复制完毕!"
 *
 *  按照上面的方式进行实现---发现文件已经上传完了,但是两端都没有结束,客户端没有接收到服务器端的反馈数据!
 *  为什么?
 *  原因:文本文本读取完毕的条件是---返回值null,作为 "文件读完"的条件,但是客户端和服务器端之间通信,底层是一种"比特流"
 *  方式数据传输的,文件读取完毕不能作为两端socket对象的接收条件!
 *
 *  解决方案:
 *      1)自己定义 客户端通道内传输的"结束条件" (不推荐)
 *      弊端:如果当前上传文本文件中有一句话"over",(代码中),文件还没有完全上传完毕,结束了!不好!
 *
 *      2)Socket客户端套接字 就提供了一个方法"public void shutdownOutput()":禁用套接字的输出流
 *              意味着"告知给服务器端,没有数据写过去了"
 *
 *
 *
 *
 */
@SuppressWarnings("all")//压制警告
public class ClientTest {
    public static void main(String[] args) throws IOException {
        //创建客户端的Socket对象
        Socket s = new Socket("10.35.165.17",8888) ;
​
        //创建字符缓冲输入流--->读源文件
        BufferedReader br = new BufferedReader(new FileReader("TCPClient.java")) ;
        //获取通道内的字节输出流
        OutputStream out = s.getOutputStream();
        //将上面的字节输出流--->封装成字符缓冲输出流
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out)) ;
​
        //一次读取一行内容--文件上传给服务器
        String line = null ;
        while((line=br.readLine())!=null){//readLine():阻塞式方法
            //通过通道内的流写给服务器
            bw.write(line) ;
            bw.newLine() ;
            bw.flush() ;
        }
​
        //方案1)自定义"通道内的传输"的结束条件
        //告诉给服务器:文件已经读完了,没有内容了
       /* bw.write("over") ;
        bw.newLine();
        bw.flush();*/
​
        //2)方案2:Socket提供的方法
        s.shutdownOutput() ;
​
        //读取服务器端的反馈
        //获取客户端所在通道内的字节输入流
        InputStream in = s.getInputStream();
        //一次读取一个字节数组
        byte[] bytes  = new byte[1024] ;
        int len = in.read(bytes) ;
        String serverFkMessage = new String(bytes,0,len) ;
        System.out.println("serverFkMessage:"+serverFkMessage);
​
​
        //释放资源
        if(br!=null){
            br.close();
        }
        if(s!=null){
            s.close();
        }
​
    }
}
package com.qf.tcp_05;
​
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
​
/**
 * @author 高圆圆
 * @date 2023/3/27 14:39
 */
@SuppressWarnings("all")
public class ServerTest {
    public static void main(String[] args) throws IOException {
        //创建服务器端的Socket
        ServerSocket ss = new ServerSocket(8888) ;
​
        //监听客户端连接
        Socket s = ss.accept();
        //获取通道内的字节输入流
        InputStream in = s.getInputStream();
        //封装成字符缓冲输入流
        BufferedReader br = new BufferedReader(new InputStreamReader(in)) ;
        //创建字符缓冲输出流对象--->操作D:\EE_2302\day29\code\copy.java 目的地文件
        BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\EE_2302\\day29\\code\\copy.java")) ;
​
        //一次读取一行
        String line = null ;
        while((line=br.readLine())!=null){ //readLine()阻塞式方法
            //读取到了"over"
           /* if("over".equals(line)){
                break;
            }*/
​
            bw.write(line) ;
            bw.newLine() ;
            bw.flush() ;
        }
​
​
        //加入反馈操作:
        //获取监听到的客户端所在通道内的字节输出流
        OutputStream out = s.getOutputStream();
        out.write("该文本文件已经上传完成".getBytes());
​
​
        //关闭资源
        if(bw!=null){
            bw.close();
        }
        if(ss!=null){
            ss.close();
        }
​
    }
}
​

客户端上传图片文件--->读取当前项目xxx.jpg图片文件---写给服务器

package com.qf.tcp_06;
​
​
import java.io.*;
import java.net.Socket;
​
/**
 * 客户端上传图片文件--->读取当前项目xxx.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();
​
​
​
​
        //关闭资源
    }
}
package com.qf.tcp_06;
​
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
​
/**
 * 服务器端--读取传过来的xx.jpg图片文件---复制到指定磁盘上的 copy.jpg文件中,服务器端加入反馈(反馈客户端)!
 *      "图片文件复制完毕"
 */
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();
    }
}
​
​

接收多个客户端的图片文件,并给出反馈 "图片上传完毕"

package com.qf.test_07;
​
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
​
/**
 * 服务器端监听多个客户端,接收多个客户端的图片文件,并给出反馈 "图片上传完毕"
 */
public class TCPClient {
    public static void main(String[] args) {
        Socket s  = null ;
        FileInputStream fis = null ;
​
        try {
            //创建客户端的Socket
            s = new Socket("10.35.165.17",10086) ;
​
            //客户端创建一个字节输入流--->FileInputStream
            fis = new FileInputStream("D:\\高圆圆.jpg") ;
​
            //获取通道内的字节输出流,写数据
            OutputStream outputStream = s.getOutputStream();
            //一次读取一个字节数组
            byte[] bytes = new byte[1024] ;
            int len = 0 ;
            while((len=fis.read(bytes))!=-1){
                outputStream.write(bytes,0,len) ;
                outputStream.flush() ;
            }
​
            s.shutdownOutput(); //告知服务器,文件已经完成写入完毕,没有流数据过去了
​
            //读取服务器端反馈的数据
            InputStream inputStream = s.getInputStream();
            byte[] buffer = new byte[1024] ;
            int length = inputStream.read(buffer);
            String fkMsg = new String(buffer,0,length) ;
            System.out.println("fkMsg:"+fkMsg);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(fis!=null){
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(s!=null){
                try {
                    s.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
​
​
    }
}
package com.qf.test_07;
​
import java.io.*;
import java.net.Socket;
​
/**
 * 服务器端接收多个客户端图片文件,并保存到指定目录下
 *
​
 */
public class UploadImageThread  implements Runnable{
    //声明Socket
    private Socket s ;
    public UploadImageThread(Socket s){ //传入获取到监听到多个客户端对象
        this.s = s ;
    }
    @Override
    public void run() {
​
        FileOutputStream fos = null ;
​
        try {
            //获取通道内的字节输入流
            InputStream in = s.getInputStream();
            //处理---同一个客户端上传的图片内容一致,但是图片名称不一致,导致之前的图片可以覆盖
            //解决上面这个问题
            String ip = s.getInetAddress().getHostAddress();
            File file = new File(
                    "D:\\EE_2302\\day29\\code\\images"+
                            ip+".jpg")  ; //10.35.165.30.jpg
            //定义一个统计变量
            int num = 1 ;
            //判断:如果file存在,---路径形式已经有了                   10.35.165.30(1).jpg
            if(file.exists()){
                file = new File("D:\\EE_2302\\day29\\code\\images"+ip+"("+(num++)+").jpg") ;
            }
​
            //指定保存的目录
            fos = new FileOutputStream(file) ;
            //一次读取一个字节数组
            byte[] bytes  = new byte[1024] ;
            int len = 0 ;
            while ((len=in.read(bytes))!=-1){
                fos.write(bytes,0,len) ;
                fos.flush() ;
            }
​
​
            //反馈给客户端
            //获取通道内的输出流
            OutputStream out = s.getOutputStream();
            out.write("图片上传完成".getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(fos!=null){
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(s!=null){
                try {
                    s.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
package com.qf.test_07;
​
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
​
/**
 * 接收多个客户端的图片文件,并给出反馈 "图片上传完毕"
 */
public class Server {
    public static void main(String[] args) {
​
        try {
            //创建服务器端的Socket
            ServerSocket ss = new ServerSocket(10086) ;
            //监听多个客户端连接
            while(true){
                Socket socket = ss.accept();
                //开启线程---->完成读取客户端上传的图片文件,保存到指定的磁盘上
                new Thread(new UploadImageThread(socket)).start();
            }
​
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
​

day30

晨写

# 晨写
​
## 1.TCP和UDP的区别
​
```markdown
1)是否建立连接通道
    TCP需要建立连接通道的
    UDP不需要建立连接通道
2)是否是可靠连接
    TCP是可靠连接,---同步的---执行效率低
    UDP是不可靠连接,---不同的--->执行效率高
3)是否传输数据大小有限制
    TCP是无限制传输,以一种"字节流"的方式
    UDP有数据大小限制(理论值64kb),以一种"数据报包"的方式
```
​
​
​
## 2.TCP客户端和服务器端进行数据传输的代码实现
​
```java
//客户端
//1)创建客户端的Socket
Socket s = new Socket("10.35.165.17",6666) ;
//2)获取通道内的字节输出流
OutputStream out = s.getOutputStream() ;
//3)写数据
out.write("hello,TCP".getBytes()) ;
//4)释放资源
s.close() ;
​
​
​
//服务器端
//1)创建服务器端的Socket
ServerSocket ss = new ServerSocket(6666) ;
//2)监听客户端连接
Socket s = ss.accept() ;
//3)获取通道 的字节输入流对象
InputStream in = s.getInputStream() ;
//4)一次读取一个字节数组
byte[] bytes = new byte[1024] ;
int len = in.read(bytes) ;
String message = new String(bytes,0,len) ;
//获取ip
String ip = s.getInetAddress().getHostAddress() ;
//展示数据
System.out.println("data from-->"+ip+",内容是:"+message) ;
//释放资源
ss.close() ;
```
​
​
​
## 3.获取一个类的字节码文件对象的方式
​
```markdown
三种方式:
    1)Object类的getClass()方法---->使用对象访问这个方法
    2)任意Java类型的class属性
    3)Class---->字节码文件对象(类对象)
        public static Class forName(String classPathname) :参数是当前类或者接口的全限定名称
                                                            包名.类名
```
​
​
​
## 4.IO流的分类
​
```markdown
BIO:阻塞式流
​
流的方向:
    输入/输出
类型:
    字节
        字节输入流
                InputStream
                            FileInputStream  文件字节输入流
                            BufferedInputStream:字节缓冲输入流
                            
                            ObjectInputStream:反序列化
        字节输出流
                OutputStream
                            FileOutputStream  文件字节输出流
                            BufferedOutputStream:字节缓冲输出流
                            
                            
                            
                            ObjectOutputStream:序列化
                            PrintStream:字节打印流
                                System.out.println("hello") ;
                                
                                PrintStream ps = System.out ;
                                ps.println("xxx") ;
                            
                            
    字符
        字符输入流
                Reader
                    InputStreamReader(InputStream in)   --->将字节输入流转换字符输入流
                        便捷类---直接操作源文件FileReadr
                    
                    BufferedReader:字符缓冲输入流
        字符输出流
                Writer
                    OutputStreamWriter(OutputStream out)--->将字节输出流转换成字符输出流
                        便捷类--->FileWriter
                    BufferedWriter:字符缓冲输出流  
                    
                    
                    PrintWriter:字符打印流
                    
NIO---->非阻塞式流----->
                    dubbo框架(发现服务/治理服务)--->底层NIO方式
​
```
​
## 5.如何读取src下面的xx.properties文件的内容
​
```java
class Demo{
    public static void main(String[] args){
        
        //src下面---类路径下 user.properties    (xx.proprties配置文件)    
                            zhangsan=30
        //获取配置文件所在字节输入流
        InputStream in =                Demo.class.getClassLoader().getResourceAsStream("user.properties") ;  
        //创建属性集合列表
        Properties prop = new Properties() ;
        //将配置文件的内容"以字节输入流"的方式加载到属性集合列表中
        prop.load(in) ;
    }
}
```
​
​
​
​
​
----
​
----
​
## 作业:io流模拟登录注册 / 网络聊天第一版:客户端/服务器端不断发/回复 
​
# 今日内容
​
## 1.补充--序列化(ObjectOutputStream)和反序列化(ObjectInputStream)
​
## 2.什么是反射?反射的基本使用 (面试题)
​
```
获取类的字节码文件对象-------------->Class
1)创建类的对象  -----> java提供类Constructor:代表这个类构造器---带参/无参
2)对象创建完毕-----> java提供类Field:代表所有的成员变量---私有的成员变量--暴力访问:赋值
3)对象创建完毕---->调用成员方法--->java提供类Method:代表所有成员方法---->调用方法
        
    自己写:    类名 对象名 = new 类名() ;
            对象名.成员变量名 = 赋值 ; //成员变量私有---不能访问
```
​
## 3.反射的应用
​
```markdown
1)有一个集合ArrayList<String>,存储了一些字符串数据了,如何给里面添加Integer类型的数据?
    add(E e)--->只能通过反射获取到add方法---所在的Method类对象
2)利用反射解决代码重复修改---->将一些内容存储到配置文件中    
```
​
## 4.反射中的常见面试题
​
## 5.数据库 
​
```
​
关系型数据库
        oralce/sqlServer/mysql... 
        (书写sql---->Structure Query Language :结构化查询语言 语句的)
非关系型数据库--->key-value键值对:Redis数据库(No SQL) ---缓存使用的
```
​
## 6.mysql数据库的安装---->mysql5.7
​
```
下载(本地安装) ---->mysql5.7(.msi安装版本或者 .zip解压版 :自己配置my.ini核心文件)
电脑上---安装 mysql server:具备mysql服务器
​
只需要用客户端去登录---连接mysql服务器
    dos窗口登录:dos中指令敲熟练
    
    图形界面化工具:---->navicat(破解)   SQLyog
```
​
​

IO流的用户登录

package com.qf.io_01;
​
import java.io.*;
​
/**
 * 序列化:就是使用ObjectOutputStream将一个Java对象的信息写入流中
 *
 *              对象--->数据流(流数据)
 * 构造方法:    public ObjectOutputStream(OutputStream out)
 * 成员方法:public final void writeObject(Object obj) :将指定的对象写入到序列化流中,变成流数据
 *
 *
 * 反系列化:就是使用ObjectInputStream 将数据流中的内容--->还原成--->对象
 * 构造方法:
 *      public ObjectInputStream(InputStream in)
 * 成员方法:
 *      public final Object readObject():从反序列流中将数据流的内容----解析成对象
 *
 */
public class ObjectStream {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
       // write() ;
​
        read() ;
    }
​
    //读:将流数据---还原成--->对象
​
    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  当前这个类未实现序列化异常
​
    }
}
package com.qf.io_01;
​
import java.io.Serializable;
​
/**
 * 学生类
 *
 * 只有支持java.io.Serializable接口的对象才能写入流中
 * 当前这个类能够实现java.io.Serializable接口---->这个类对象就可以被序列化(对象---流数据)
 * java提供一些接口:如果字段,连成员方法都没有,都称为"标记接口"
 *
 *
 * 序列化的时候--->当前类的所有的成员(成员变量/成员方法/构造方法等等)---->内存中--->"类的签名信息" 序列化的ID值
 * 如果反序列化的时候,修改了类的成员信息,会导致和之前序列化的信息不一致:就会出现
 * java.io.InvalidClassException:序列化中的序列化版本UID值和反序列化的UID值不相同(类的签名信息不一致)
 *
 */
public class Student implements Serializable {
​
    //生成固定的序列化的版本Id
    private static final long serialVersionUID = -5794781839275410852L;
    String name ;
    transient int age ;  //transient 让这个字段(属性) 不参与序列化和反序列化
​
    public Student() {
    }
​
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
​
    public String getName() {
        return name;
    }
​
    public void setName(String name) {
        this.name = name;
    }
​
    public int getAge() {
        return age;
    }
​
    public void setAge(int age) {
        this.age = age;
    }
​
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
​

反射

package com.qf.reflect_02;
​
/**
 * 什么是反射? (jvm正在编译的时候,就可以获取这个类所有的信息!)
 *      (Reflection),一个类在加载运行状态的时候,可以动态获取正在运行的类(Class)
 * 创建正在运行类的对象(构造器-Constructor)
 * 使用正在运行的这个类的对象去给 成员变量赋值(Field)
 * 调用正在运行的这个类中成员方法(Method)
 *
 * 反射应用----Java设计模式
 *
 * 正射 ----就是我们自己书写的代码的时候, 类名 对象名 =  new 类名() ;
 *
 *
 * 面试题:
 *      获取一个类的字节码文件的方式?
 *          1)调用Object类的getClass方法
 *          2)任意Java类型的class属性
 *
 *          3)第三种方式:(推荐)
 *
 *                 Java提供类Class:表示正在运行的Java应用程序中的类和接口
 *                 有一个静态方法:
 *                           参数:类的完全限定名称。 (包名.类名) String类型:经常用在配置文件中xx.properties
 *                          public static Class<?> forName(String className):
 *
 */
public class ReflectDemo {
    public static void main(String[] args) throws ClassNotFoundException {
        //创建当前类对象
        Person p = new Person() ;
        System.out.println(p.getClass()) ;//class com.qf.reflect_02.Person
        Class c2 = Person.class ;
        System.out.println(c2) ;
        System.out.println(p.getClass() ==c2) ;
        System.out.println("-----------------------------") ;
//        Class<?> c3 = Class.forName("Person");//参数必须:类的全限定名称
        Class<?> c3 = Class.forName("com.qf.reflect_02.Person");
        System.out.println(c3);
        System.out.println(c3==c2);
    }
}
package com.qf.reflect_02;
​
import java.lang.reflect.Constructor;
​
/**
 *  (Reflection),一个类在加载运行状态的时候,可以动态获取正在运行的类(Class)
 *  然后--->创建当前类对象
 *
 *  正常在写代码:
 *          Person p = new Person() ; //创建Person类的对象
 */
public class ReflectDemo2 {
    public static void main(String[] args)  throws Exception{
        System.out.println("正常的创建对象的格式:");
​
        Person p  = new Person() ;
        System.out.println(p);
​
        System.out.println("---------------------反射的方式:动态获取类的构造器并创建实例---------------------------------");
        //1)获取正在运行的类的字节码文件对象
        Class c = Class.forName("com.qf.reflect_02.Person");
        //2)public Constructor<?>[] getConstructors()throws SecurityException
        //获取正在运行的类中的所有公共的构造方法所在的Constructor类对象
        //public Constructor<?>[] getDeclaredConstructors():
        //获取正在运行的类中所有的构造方法所在的Constructor类对象
//        Constructor[] cons = c.getConstructors();
       /* Constructor[] cons = c.getDeclaredConstructors();
        for(Constructor con:cons){
            System.out.println(con);
        }*/
​
        //2)获取指定的构造器的Constructor对象,创建当前类实例
        //public Constructor<T> getConstructor(Class<?>... parameterTypes)
        //获取指定的公共的构造方法的Constructor对象,参数:指定参数类型的Class类对象,如果没有参数,可以不写
                        //举例:String类型的参数---java.lang.String
                        //int---->java.lang.Integer
        Constructor con = c.getConstructor() ;
        //System.out.println(con);//public com.qf.reflect_02.Person()
        //Constructor提供一个方法
        //参数:通过构造器里面给当前正在运行的类的成员变量赋值:实际参数
        //返回T---Type:代表任意Java对象
        //public T newInstance(Object... initargs):创建当前类实例
        Object obj = con.newInstance() ; // 多态 类似于 --->Object obj = new  Person() ;
        System.out.println(obj);
        //Person p2 = (Person) obj;
       // System.out.println(p2) ;
​
​
        System.out.println("----------------通过有参构造方法当前类实例---------------------------------");
        //Person person = new Person("高圆圆",44,"西安市") ;// 正常:私有不能直接创建
​
        //通过当前类的字节码文件对象获取指定的构造方法
        //参数是:当前参数类型的字节码文件 String--->String.class
        //public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
        Constructor con2 = c.getDeclaredConstructor(String.class, int.class, String.class);
        //System.out.println(con2);
​
        //构造器所在Constructor继承AccessibleObject 提供
        // public void setAccessible(boolean flag) :参数为true:取消Java语言访问检查
        con2.setAccessible(true) ;
        //public T newInstance(Object... initargs):创建当前类实例
        Object obj2 = con2.newInstance("高圆圆", 44, "西安市南窑国际") ;
        System.out.println(obj2) ;
​
​
    }
​
    //public static void get(int...a){ //a代表多个参数:可变参数(当不明确具体有多个参数的时候,可以使用...)
​
    //}
}
​

现在通过反射获取指定的类的字节码文件对象并去给类的成员变量进行赋值

package com.qf.reflect_03;
​
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
​
/**
 *现在通过反射获取指定的类的字节码文件对象并去给类的成员变量进行赋值
 *
 * 之前的写法:
 *          Person p = new Person() ;
 *          属性没有私有
 *          p.name = "高圆圆" ;
 *          p.age = 44 ;
 *          p.address = "西安市" ;
 */
public class ReflectDemo3 {
​
    public static void main(String[] args) throws Exception {
​
        //获取当前类的字节码文件对象
        Class c = Class.forName("com.qf.reflect_02.Person") ;
        //Person类的无参构造方法本身就公共的
        //两种方案创建类的实例
        //1)获取这个类的无参构造方法所在的Constructor--->T newInstance()
       /* Constructor constructor = c.getConstructor();
        Object obj2 = constructor.newInstance();
        System.out.println(obj2);*/
        //2)可以直接使用当前类的字节码文件对象Class--->public T newInstance()
        Object obj = c.newInstance();
        System.out.println(obj);
​
        //public Field[] getFields():获取所有的公共字段(成员变量)
        //public Field[] getDeclaredFields():获取"这个类"所有的字段所在的Field类对象,公共的/默认的/私有的/受保护的
       /* Field[] fields = c.getDeclaredFields();
        for(Field field :fields){
            System.out.println(field);
        }*/
​
        //通过这个类Class字节码文件对象获取当前类的指定的成员变量的Field类对象
        //public Field getDeclaredField(String name) 参数:这个类的属性名称
        Field nameField = c.getDeclaredField("name");
        //System.out.println(nameField);
​
        //取消Java语言访问检查功能
        nameField.setAccessible(true) ;
        //Field:代表类的字段(成员变量)
        //public void set(Object obj,Object value):将指定的value实际参数作用在指定的当前类的实例上
        nameField.set(obj,"高圆圆") ;//java.lang.IllegalAccessException:非法访问:name 是私有的
        System.out.println(obj) ;
​
        System.out.println("-------------------------------------------") ;
        //age/address进行赋值
        //获取指定age字段的Field类对象
        Field ageField = c.getDeclaredField("age");
        //取消Java语言访问检查
        ageField.setAccessible(true) ;
        //赋值
        ageField.set(obj,44) ;
        System.out.println(obj);
​
        System.out.println("--------------------------------") ;
        Field addressField = c.getDeclaredField("address");
        //取消Java语言访问检查
        addressField.setAccessible(true) ;
        //赋值
        addressField.set(obj,"鄠邑区") ;
        System.out.println(obj) ;
    }
}
​

动态获取指定类的字节码文件对象,创建当前类实例,调用里面的指定的成员方法!

package com.qf.reflect_03;
​
import com.qf.reflect_02.Person;
​
import java.lang.reflect.Method;
​
/**
 * 动态获取指定类的字节码文件对象,创建当前类实例,调用里面的指定的成员方法!
 *
 * 之前写:
 *              Person p = new Person() ;
 *              p.show("javaee") ;
 */
public class ReflectDemo4 {
​
    public static void main(String[] args) throws Exception{
        System.out.println("-------------之前的写法-----------") ;
        Person p = new Person() ;
        p.show("helloworld") ;
​
        System.out.println("------------------反射的方式-------------------------");
​
        //1)获取指定类的字节码文件对象
        Class c = Class.forName("com.qf.reflect_02.Person") ;
        //2)无参构造方法公共的,Person类中,字节创建当前类实例
        Object obj = c.newInstance() ;
        //public Methods[] getMethods():获取这个类的所有的公共的成员方法的类对象Method(包括继承过来的以及实现接口的方法)
        //public Methods[] getDeclaredMethods():获取类所有的的指定的成员方法的类对象Method,不包括继承过来的
​
        //3)获取指定的公共成员方法
        //public Method getMethod(String name,Class<?>... parameterTypes)
        //参数1:方法的名称
        //参数2:当前方法中参数类型的Class
        Method m = c.getMethod("show", String.class);//参数2:java.lang.String
        //System.out.println(m);
​
        //4)调用方法
        //Method--->public Object invoke(Object obj,Object... args)
        //参数1:这个类的实例
        //参数2:方法中传入的实际参数
        m.invoke(obj, "helloworld");//本身这个方法没有返回值,可以不写;有返回值,使用Object类型接收
​
        System.out.println("-------------------------------------------------") ;
        //调用method方法
        //获取指定的成员方法所在的类对象Method
        //public Method getDeclaredMethod(String name,Class<?>... parameterTypes)
        Method m2 = c.getDeclaredMethod("method", int.class) ;
        //System.out.println(m2) ;
​
        //取消Java语言检查
        m2.setAccessible(true) ;
        //调用方法
        Object returnObj = m2.invoke(obj, 100);
        System.out.println(returnObj);
​
        //其他方法调用
​
​
​
    }
}
​

用反射来进行文件传输

package com.qf.reflect_test_01;
​
import com.sun.corba.se.spi.orbutil.threadpool.Work;
​
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Properties;
​
/**
 * 测试类
 *
 * 开发原则:所有开发原则必须"低耦合,高内聚"
 *      开闭原则:
 *              对现有代码的修改进行关闭,对扩展开放!
 */
public class ReflectTest {
    public static void main(String[] args) throws Exception {
        //使用学生的love方法
        /*Student s = new Student() ;
        s.love() ;*/
​
        //切换为工人类的love方法
        Worker worker = new Worker() ;
        worker.love();
​
        System.out.println("--------------------------------------------") ;
        //使用反射:--src下面提供xx.properties配置文件
        //创建一个属性集合列表---空的
        Properties prop = new Properties() ;
        //读取src西玛的配置文件
        InputStream inputStream = ReflectTest.class.getClassLoader().
                getResourceAsStream("my.properties");
​
        //将配置文件中的内容 以"字节输入流"的方式加载到属性集合列表中
        prop.load(inputStream);
//        System.out.println(prop);
​
        //通过属性集合列表特有功能:getProperty(String key)---获取String value
        String className = prop.getProperty("className");
        //System.out.println(className) ;
        String methodName = prop.getProperty("methodName");
        //System.out.println(methodName);
​
        //通过反射获取当前类的字节码文件对象
        Class c = Class.forName(className) ;//class com.qf.reflect_test_01.Student
        //直接创建当前类实例
        Object obj   = c.newInstance();//等价于字节码文件对象获取无参构造方法的Constructor类对象--->Object newIntance()
        //System.out.println(obj);
​
        //获取当前类的成员方法的method类对象
        Method method = c.getDeclaredMethod(methodName);
        //调用方法
        method.invoke(obj) ;
​
    }
}
package com.qf.reflect_test_01;
​
/**
 * 学生类
 */
public class Student {
    public void love(){
        System.out.println("爱学习,爱Java!");
    }
}
package com.qf.reflect_test_01;
​
/**
 * 工人类
 */
public class Worker {
    public void love(){
        System.out.println("爱生活,爱高圆圆!");
    }
}
​

day31

晨写

1.什么是单例设计模式,有哪两种,分别什么有特点

单例设计模式:
    始终在内存只有当前这个类或者接口的一个实例;
分为:
    饿汉式和懒汉式
    
饿汉式的特点(不会出现安全的单例模式)
    1)当前类具体类
    2)这个一加载,就创建当前类的静态实例(私有的)
    3)构造方法私有化--外界不能new
    4)对外提供静态的公共方法,返回值是当前类本身!
懒汉式的特点(可能出现线程安全问题的一种单例设计模式)
    1)当前类具体类
    2)当类的成员位置:声明私有的当前类的变量 (静态的) 
    3)构造私有化--外界不能new
    4)对外提供静态的公共方法,返回值是当前类本身
            需要对当前类的变量进行判断,如果为null, 才创建当前类实例
            返回当前类实例;
            
class Student{
    private static Student s ; 
    private Student(){}
    
    public synchronized static Student getInsance(){//静态的同步方法,解决线程安全问题!
        if(s==null){//需要用的时候才创建对象
            s = new Student() ;
        }
        return s ;
    }
}

2.什么是反射?

​
    某一个类在运行状态中,可以动态的获取类的字节码文件同时创建当前类实例,可以调用成员方法,去动态去给成员变量进行赋值;--满足Java语言特点 "动态性"----->就可以在运行过程某个类或者接口的成员方法,来完成一种
"动态代理"
        jdk动态代理--->前提必须有接口
        cglib动态代理

3.如何获取一个类的构造器并去创建对象?

//1)获取这个类的字节码文件对象
Class c = Class.forName("类的完全限定名称-就是包名.类名") ;
//2)获取私有的构造方法所在的Constructor类对象---带有两个参数:String和int类型
Constructor con = c.getDeclaredConstructor(String.class,int.class) ;
//3)防止出现非法访问异常--->取消Java语言访问检查
con.setAccessiable(true) ;
//4)创建当前类实例:使用Constructor类对象
Object obj = con.newInstance("高圆圆",44) ;

4.如何获取一个类的成员变量所在的Field类对象,去给成员变量赋值

//Constructor:代表构造方法的类对象
//Field:代表成员变量的Field类对象
//Method:代表成员方法的Method类对象
//---->如果访问私有,必须都取消java语言检查!
​
//1)获取这个类的字节码文件对象
Class c = Class.forName("类的完全限定名称-就是包名.类名") ;
//2)假设如果当前类的无参构造方法--公共的或者是你没用提供任何构造方法,系统会默认提供公共的无参构造方法
//可以直接创建当前类实例
Object obj = c.newInstance() ;
​
//3)获取私有的属性(成员变量)所在Field类对象
Field field = c.getDeclaredField("属性名称") ;//String类型的属性
//4)取消Java语言访问检查
field.setAccessiable(true) ;
//5)赋值
field.set(obj,"高圆圆") ;

5.获取一个类的成员方法所在的Method类对象,去调用方法

(使用反射思想解决问题---使用反射调用成员方法 (使用最多))

//1)获取这个类的字节码文件对象
Class c = Class.forName("类的完全限定名称-就是包名.类名") ;
//2)假设如果当前类的无参构造方法--公共的或者是你没用提供任何构造方法,系统会默认提供公共的无参构造方法
//可以直接创建当前类实例
Object obj = c.newInstance() ;
​
/*
public String getAnimalMessage(Animal a){
        return a.getName() ; //获取动物名称;
}
*/
​
//3)通过字节码文件对象获取类的成员方法的Method类对象 --私有的
Method m = c.getDeclaredMethod("getAnimalMessage",Animal.class) ;//假设本身成员方法:带有一个参数 Animal类型(引用类型)
//4)取消Java语言访问检查
m.setAccessiable(true) ;
//调用方法
Class c2 = Class.forName("包名.Animal") ; //Animal类的无参构造方法也是公共的
Object obj2 = c2.newInstance();
​
Object returnObj = m.invoke(obj,obj2) ;


今日内容

1.网络聊天---TCP协议完成客户端/服务器端不断发和回复消息

2.反射的应用

    有一个ArrayList集合里面存储的都是String,ArrayList<String>
​
    如何通过反射给里面存储Integer类型的元素

3.反射的jdk动态代理(理解并且掌握)

//前提接口:
    interface UserDao{
            void add() ;//添加用户
            void update() ;//修改用户
            void findAll();//查询所有
            void delete() ;//删除
                
    }
​
class UserDaoImpl implements UserDao{
    
    publid void add(){
        //对添加操作:进行增强---(添加之前)权限校验  --->系统监控代码---和下面的业务完全分离!
        System.out.println("添加用户") ;
    }
}

4.什么是数据库,常见的数据库有哪些/数据库的特点

5.MySql它的基本操作:DDL语句:数据库定义语句

现在dos窗口/要么mysql5.7自带的客户端窗口---->"黑窗口" 使用基本语句
库-->在电脑磁盘--就是一个文件夹
创建库/删除库/查询库的字符集/修改库的字符集
创建表/删除表/修改表的字段名称/修改表的字段类型/添加一个字段/复制一张表/修改表的名称.../查询表的结构

6.DML语句:数据库操作语句

有库,有了表--->操作表的记录
添加数据
删除数据
修改数据

DQL:数据库查询语句(语法最多)

mysql卸载:控制面板卸载
     c隐藏文件夹programmData--MySQL删除
 win+r---->regedit--->进入注册
 计算机\HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\MySQL57
  计算机\HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\EventLog\MySQL57
 计算机\HKEY_LOCAL_MACHINE\SYSTEM\ControlSet002\Services\MySQL57
  计算机\HKEY_LOCAL_MACHINE\SYSTEM\ControlSet002\Services\EventLog\mysq57
 计算机\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\MYSQL57
 计算机\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\mysql57
 
 



数据库

存储的数据的仓库
	最早开始存储:定义临时变量 int a = 10 ; 
	数组存储数据:弊端长度固定
	StringBuffer:可以存储数据---字符序列---->转换成String
	Collection/Map:存储一些元素或者键值元素,集合创建完毕,使用完毕也就不存在了
	IO流可以永久的存储数据,IO--写数据---读数据(字节流)耗时 (本地存储)

常见的数据库

	
	使用数据库DataBase(db)存储数据 :
	分为:
		关系型数据库:		支持"事务系统":读/写的过程:保证数据的安全性/一致性
						支持高并发访问 :同时多个同时访问数据库 
						存储大类型数据: 大字节类型/大字字符类型
						
				oracle/sqlServer/MySql/SQLite(轻量级的关系型数据库)/mariaDB
				中小型企业:mysql居多 (InnoDB---存储引擎:支持行级锁)
				大公司:Oracle居多
		非关系数据库
				常见noSQL数据库:没有sql语句
				redis---->作为 "缓存用户的"    (三阶段后期/四阶段前期)
						key-value元素存储进去 

常见关系型数据库的sql语法很类似

操作数据库定义语句DDL

操作库:
	1)查询所有库
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |  --mysql自带配置信息相关的库文件(_schema约束文件)
| mysql              |	--有mysql里面user用户相关的信息表数据:root用户或者添加普通用户
| performance_schema |	--mysql数据库本身自带的优化mysql性能相关的
| sys                |	-- mysql系统相关的库文件
+--------------------+
4 rows in set (0.00 sec)
	2)创建一个新的数据库
	2.1)create database 库名;  直接创建
mysql> create database mydb01;
Query OK, 1 row affected (0.01 sec)

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mydb01             |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.00 sec)
	2.2)create database if not exists 库名;   判断不存在库才创建
mysql> create database if not exists mydb_02;
Query OK, 1 row affected (0.00 sec)

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mydb01             |
| mydb_02            |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
6 rows in set (0.00 sec)	

	3)查看创建指定库的字符集编码格式
	show create database 库名;
mysql> show create database mydb01;
+----------+-------------------------------------------------------------------+
| Database | Create Database                                                   |
+----------+-------------------------------------------------------------------+
| mydb01   | CREATE DATABASE `mydb01` /*!40100 DEFAULT CHARACTER SET latin1 */ |
+----------+-------------------------------------------------------------------+
1 row in set (0.01 sec)
	4)修改指定库的字符集格式 
	alter database 库名 (default) character set 字符集格式;
mysql> alter database mydb01 default character set = utf8;
Query OK, 1 row affected (0.01 sec)

mysql> show create database mydb01;
+----------+-----------------------------------------------------------------+
| Database | Create Database                                                 |
+----------+-----------------------------------------------------------------+
| mydb01   | CREATE DATABASE `mydb01` /*!40100 DEFAULT CHARACTER SET utf8 */ |
+----------+-----------------------------------------------------------------+
	5)删除库
	5.1)drop database 库名; 直接删除
mysql> drop database mydb01;
Query OK, 0 rows affected (0.03 sec)

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mydb_02            |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.00 sec)

	5.2)drop database if exists 库名; 判断存在库名,直接删除
mysql> drop database if exists mydb_02;
Query OK, 0 rows affected (0.00 sec)

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
4 rows in set (0.00 sec)

mysql>

	6)进入到指定的库中--使用这个库
	use 库名;---提示 "database changed"表示正在使用
mysql> use ee2302;
Database changed
	7)mysql字段的查询正在使用库的函数 select database() ;
mysql> select database();
+------------+
| database() |
+------------+
| ee2302     |

+------------+
1 row in set (0.00 sec)

数据库中表的创建/删除/修改/查询DDL语句

常见的数据表的字段类型:
	1)int :整数类型   默认11位     里面所占的实际值  (推荐)
					age年龄字段   ----20
	  int(指定的字符数)  
	  		int(3) 指定当前值的位数3位    1--->001 (不推荐,八进制0开头)
	2)字符串 varchar(指定最大长度)
    			name字段---varchar(10)  :最大长度10位
    3)小数类型 double  
    		  double(3,1)---小数是3位,小数点后保留一位数
    		  
    4)日期类型 date	仅仅表示日期
    		  datetime:日期+时间
    		  timestamp:时间戳(某个时间点去操作了数据库中某个表或者某个表的记录的时间 )或者瞬时时间
    		  
	
	
	1.创建表的语法----创建表之前,选库(use 库名;)
	create table 表名(
		字段名称1 字段类型1,
		字段名称2 字段类型2,
		字段名称3 字段类型3,
		...,
		字段名称n 字段类型n) ;
 创建一个学生表
 mysql> create table student(
    -> id int,
    -> name varchar(10),
    -> age int,
    -> gender varchar(3),
    -> address varchar(50),
    -> birthday date);
Query OK, 0 rows affected (0.05 sec)

	2.查询库中的所有表 
	show tablse;
mysql> show tables;
+------------------+
| Tables_in_ee2302 |
+------------------+
| student          |
+------------------+
1 row in set (0.00 sec)
	3.查询表的结构:查询这个表的"列"有哪些
	desc 表名;
mysql> create table student(
    -> id int,
    -> name varchar(10),
    -> age int,
    -> gender varchar(3),
    -> address varchar(50),
    -> birthday date);
Query OK, 0 rows affected (0.05 sec)

mysql> show tables;
+------------------+
| Tables_in_ee2302 |
+------------------+
| student          |
+------------------+
1 row in set (0.00 sec)
	4.修改表---修改的表的字段名称(列的名称)
	alter table 表名 change 以前的字段名称 现在的新的字段名称 以前的字段类型;
mysql> alter table student change gender sex varchar(3);
Query OK, 0 rows affected (0.03 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> desc student;
+----------+-------------+------+-----+---------+-------+
| Field    | Type        | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| id       | int(11)     | YES  |     | NULL    |       |
| name     | varchar(10) | YES  |     | NULL    |       |
| age      | int(11)     | YES  |     | NULL    |       |
| sex      | varchar(3)  | YES  |     | NULL    |       |
| address  | varchar(50) | YES  |     | NULL    |       |
| birthday | date        | YES  |     | NULL    |       |
+----------+-------------+------+-----+---------+-------+
6 rows in set (0.00 sec)
	4.1 修改表---修改表的字段类型
	alter table 表名 modify address 对应的新的字段类型;
mysql> alter table student modify address varchar(20) ;
Query OK, 0 rows affected (0.08 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> desc student;
+----------+-------------+------+-----+---------+-------+
| Field    | Type        | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| id       | int(11)     | YES  |     | NULL    |       |
| name     | varchar(10) | YES  |     | NULL    |       |
| age      | int(11)     | YES  |     | NULL    |       |
| sex      | varchar(3)  | YES  |     | NULL    |       |
| address  | varchar(20) | YES  |     | NULL    |       |
| birthday | date        | YES  |     | NULL    |       |
+----------+-------------+------+-----+---------+-------+
6 rows in set (0.01 sec)
	4.2)修改表---给表中添加一个新的字段名称(新的列)
	alter table 表名 add 字段名称 字段类型;
mysql> alter table student add zipcode varchar(10) ;
Query OK, 0 rows affected (0.07 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> desc student;
+----------+-------------+------+-----+---------+-------+
| Field    | Type        | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| id       | int(11)     | YES  |     | NULL    |       |
| name     | varchar(10) | YES  |     | NULL    |       |
| age      | int(11)     | YES  |     | NULL    |       |
| sex      | varchar(3)  | YES  |     | NULL    |       |
| address  | varchar(20) | YES  |     | NULL    |       |
| birthday | date        | YES  |     | NULL    |       |
| zipcode  | varchar(10) | YES  |     | NULL    |       |
+----------+-------------+------+-----+---------+-------+
7 rows in set (0.00 sec)
	4.3)修改表---将表中的字段名称删除
	alter table 表名  drop 字段名称;
mysql> alter table student drop zipcode;
Query OK, 0 rows affected (0.05 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> desc student;
+----------+-------------+------+-----+---------+-------+
| Field    | Type        | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| id       | int(11)     | YES  |     | NULL    |       |
| name     | varchar(10) | YES  |     | NULL    |       |
| age      | int(11)     | YES  |     | NULL    |       |
| sex      | varchar(3)  | YES  |     | NULL    |       |
| address  | varchar(20) | YES  |     | NULL    |       |
| birthday | date        | YES  |     | NULL    |       |
+----------+-------------+------+-----+---------+-------+
6 rows in set (0.00 sec)
	5.复制一张一模一样的表
	create table 新的表名 like 旧表名;
mysql> create table teacher like student;
Query OK, 0 rows affected (0.03 sec)

mysql> show tables;
+------------------+
| Tables_in_ee2302 |
+------------------+
| student          |
| teacher          |
+------------------+
2 rows in set (0.00 sec)

mysql> desc teacher;
+----------+-------------+------+-----+---------+-------+
| Field    | Type        | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| id       | int(11)     | YES  |     | NULL    |       |
| name     | varchar(10) | YES  |     | NULL    |       |
| age      | int(11)     | YES  |     | NULL    |       |
| sex      | varchar(3)  | YES  |     | NULL    |       |
| address  | varchar(20) | YES  |     | NULL    |       |
| birthday | date        | YES  |     | NULL    |       |
+----------+-------------+------+-----+---------+-------+
6 rows in set (0.00 sec)
	6.删除表 
	6.1)drop table 表名 ;直接删除
	mysql> drop table teacher;
Query OK, 0 rows affected (0.02 sec)

mysql> show tables;
+------------------+
| Tables_in_ee2302 |
+------------------+
| student          |
+------------------+
1 row in set (0.00 sec)
	6.2)drop table if exists 表名; 如果存在这个表,删除
mysql> drop table if exists student;
Query OK, 0 rows affected (0.02 sec)

mysql> show tables;
Empty set (0.00 sec)

mysql>





mysql:查询mysql服务器中所有的跟字符集相关的指令:模糊搜索
show variables like '%character%' ;


mysql> show variables like '%character%' ;
+--------------------------+---------------------------------------------------------+
| Variable_name            | Value                                                   |
+--------------------------+---------------------------------------------------------+
| character_set_client     | gbk                                                     |
| character_set_connection | gbk                                                     |
| character_set_database   | utf8(创建的所有库默认字符集utf8)                                                    |
| character_set_filesystem | binary                                                  |
| character_set_results    | gbk                                                     |
| character_set_server     | utf8 (服务器端)                                                |
| character_set_system     | utf8(mysql系统字符集)                                                    |
| character_sets_dir       | C:\Program Files\MySQL\MySQL Server 5.7\share\charsets\ |
+--------------------------+---------------------------------------------------------+
8 rows in set, 1 warning (0.01 sec)

需求:有一个ArrayList集合里面存储的都是String,ArrayList<String>

如何通过反射给里面存储Integer类型的元素

package com.qf_test_01;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;

/**
 *需求:
 *  有一个ArrayList集合里面存储的都是String,ArrayList<String>
 * 如何通过反射给里面存储Integer类型的元素
 */
public class ReflectTest {
    public static void main(String[] args) throws NoSuchMethodException,
            InvocationTargetException, IllegalAccessException {

        //创建一个ArrayList
        ArrayList<String> arrayList = new ArrayList<>() ;
        arrayList.add("hello") ;
        arrayList.add("world") ;
        arrayList.add("JavaEE") ;
        System.out.println(arrayList);
//        arrayList.add(100) ;

        //通过反射的方式,给里面添加任何元素,调用add(Object obj)
        Class c = arrayList.getClass() ;
        //System.out.println(c) ;

        //通过字节码文件对象获取add方法所在的Method类对象
        Method m = c.getDeclaredMethod("add", Object.class) ;

        //取消Java语言访问检查
        m.setAccessible(true) ;
        //直接调用方法,里面传入实际参数
        m.invoke(arrayList,100) ;
        m.invoke(arrayList,'A') ;
        m.invoke(arrayList,12.56) ;
        System.out.println(arrayList);


    }
}

静态代理->动态代理

package com.qf_reflect_02;

/**
 * 针对用户的数据访问接口
 *  这个接口有针对用户的添加,删除,修改,查询的功能
 */
public interface UserDao {

    /**
     * 添加用户操作
     */
    void add() ;

    /**
     * 修改用户
     */
    void update() ;

    /**
     * 删除用户
     */
    void delete() ;

    /**
     * 查询所有用户
     */
    void findAll() ;
}
package com.qf_reflect_02;

/**
 * 针对用户的数据接口实现
 */
public class UserDaoImpl  implements UserDao{
    /**
     * 添加用户操作
     */
    @Override
    public void add() {
        System.out.println("添加用户操作") ;
    }

    /**
     * 修改用户
     */
    @Override
    public void update() {
        System.out.println("修改用户") ;
    }

    /**
     * 删除用户
     */
    @Override
    public void delete() {
        System.out.println("删除用户") ;
    }

    /**
     * 查询所用
     */
    @Override
    public void findAll() {
        System.out.println("查询所有用户") ;
    }
}

package com.qf_reflect_02;

/**
 * 优化之后的实现类:对add/delete/udate/findAll这些功能进行增强!
 */
public class UserDaoImpl2  implements UserDao{
    private  UserDao ud ;
    public UserDaoImpl2(UserDao ud){
        this.ud = ud ;
    }
    @Override
    public void add() {
        System.out.println("权限校验") ; //---->第三方提供的: 系统监控代码 shiro框架:权限框架/SpringSecurity权限框架
        //自己的业务功能
        ud.add() ;
        System.out.println("产生日志记录");
    }

    @Override
    public void update() {
        System.out.println("权限校验" ) ;
        //自己的业务功能
        ud.update(); ;
        System.out.println("产生日志记录");
    }

    @Override
    public void delete() {
        System.out.println("权限校验" ) ;
        //自己的业务功能
        ud.delete(); ;
        System.out.println("产生日志记录");
    }

    @Override
    public void findAll() {
        System.out.println("权限校验" ) ;
        //自己的业务功能
        ud.findAll(); ;
        System.out.println("产生日志记录");
    }
}
package com.qf_reflect_02;

import com.jdkproxy_03.MyInvocationHandler;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

/**
 * 测试类
 * 提供好了一个接口,---对用户的添加删除修改查询的功能
 * 在具体的实现类中进行实现类;
 * 需求:
 *      想对添加/删除/修改/查询的功能之前,完成一些事情 "权限校验"功能,操作这些业务方法之后,产生"日志记录"这些事情!
 *
 *
 *   代理设计模式---属于"结构型设计模式"
 *   代理核心思想:代理角色帮助真实角色对他的业务功能进行增强!
 *              静态代理
 *                      特点:代理角色和真实角色必须实现同一个接口!
 *                      弊端:业务功能和 增强的功能没有完全分离!
 *              动态代理
 *                      jdk动态代理--->jdk提供的
 *                                      java.lang.reflect.Proxy:动态代理类
 *                           静态方法:
 *                                  public static Object newProxyInstance(
 *                                        ClassLoader loader, //获取接口实例的类加载器
 *                                       Class<?>[] interfaces,//实现的接口列表的字节码文件(代理类要的实现接口列表的Class)
 *                                       InvocationHandler h)//有代理实例调用 接口方法的处理程序:接口类型 throws IllegalArgumentException
 *                 InvocationHandler:接口
 *                public Object invoke(Object proxy, Method method, Object[] args)
 *                          参数1:调用该方法的代理实例
 *                          参数2:调用该代理实例的接口方法的Method类对象
 *                          参数3:调用接口方法中所有的参数,组成数组,没有参数,可不写
 *
 *
 *
 *
 *                      cglib动态代理----不需要接口,基于类就可以实现动态代理
 *                      必须提供第三方jar包  (cglib-3.3.0.jar)
 *
 *
 */
public class UserTest {
    public static void main(String[] args) {
        //创建UserDao接口对象---子实现类创建
        UserDao ud = new UserDaoImpl() ; //ud:真实角色
        ud.add() ;
        ud.update() ;
        ud.delete() ;
        ud.findAll();
        System.out.println("------------------优化后:对业务功能增强(静态代理)-------------------") ;
        UserDaoImpl2 ud2 = new UserDaoImpl2(ud) ; //代理角色
        ud2.add() ;
        ud2.delete();
        ud2.update();
        ud2.findAll();

        System.out.println("---------------------JDK动态代理实现--------------------------------------------") ;

        //接口多态
        InvocationHandler handler = new MyInvocationHandler(ud) ;
        UserDao ud3 = (UserDao) Proxy.newProxyInstance(
                ud.getClass().getClassLoader(),//代理实例要实现的接口的字节码文件---类加载
                //代理实例要实现接口列表的Class--->Class类中--public 类<?>[] getInterfaces()
                ud.getClass().getInterfaces(),
                //代理实例调用接口方法的处理程序
                handler);

        ud3.add() ;
        ud3.delete() ;
        ud3.update() ;

        ud3.findAll() ;
    }
}
package com.jdkproxy_03;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * 自定义一个类实现InvocationHandler接口
 * 实现invoke方法---->就是调用接口方法
 *
 * 代理实例要调用接口方法的处理程序
 */
public class MyInvocationHandler implements InvocationHandler {

    //声明Object变量
    private  Object  target ;
    public MyInvocationHandler(Object target){// 传入真实角色
        this.target =  target ;
    }

    /**
     *
     *
     *
     *
     * @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

package com.qf.chatroom.client;

import com.qf.chatroom.thread.ClientReadThread;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;

/**
 * 网络聊天:
 *      TCP方式---保证安全(可靠连接,建立连接通道)
 *     客户端不断的发送消息,不断的去读取服务器端反馈的消息!
 */
public class Client {

    public static void main(String[] args) {
        try {
            //创建客户端的Socket对象
            Socket socket  = new Socket("10.35.165.17",8888) ;
            //获取客户端所在的通道内的字节输入和字节输出流
            OutputStream out = socket.getOutputStream() ;
            InputStream in = socket.getInputStream();

            //创建键盘录入对象
            Scanner sc = new Scanner(System.in) ;

            //客户端开启读取服务器回复的消息的子线程
            ClientReadThread crt = new ClientReadThread(socket)  ;
            crt.start() ;

            //不断的去发送消息
            while (true){
                System.out.println("请发送消息:" );
                String message = sc.nextLine() ;
                //约定客户端发送消息的格式: "接收者:消息内容:发送者"  (:英文符号)

                out.write(message.getBytes()) ;

                //读取服务器反馈的消息
                /*byte[] bytes = new byte[1024] ;
                int len = in.read(bytes);
                String fkMessage = new String(bytes,0,len) ;
                //展示服务器反馈的消息
                System.out.println(fkMessage);*/
            }



            /**
             * 在用户线程main中,客户端和服务器端都一样,既去写消息,又要读消息,
             * read方法本身就是阻塞式方法,如果服务器端监听多个客户端,多个客户端同时去给服务器端消息,可能消息阻塞现象!
             * 不安全!--------->开启多线程的方式
             *          一般子线程中:"读消息",不会录入的消息 (main用户线程中录入)
             *          客户端和服务器端---分别开启读消息的子线程-----使用 继承Thread类实现
             */


        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
package com.qf.chatroom.thread;

import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;

/**
 * 客户端读取服务器发送过来的消息的子线程
 */
public class ClientReadThread extends Thread {
    private Socket s ;

    public ClientReadThread(Socket s) {
        this.s = s ;
    }

    @Override
    public void run() {
        //不断的去读
        try {
            while(true){
                //获取客户端通道内的字节输入流
                InputStream in = s.getInputStream();

                byte[] bytes = new byte[1024] ;
                int len = in.read(bytes);
                String fkMessage = new String(bytes,0,len) ;
                //展示服务器反馈的消息
                System.out.println(fkMessage);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(s!=null){
                try {
                    s.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }


    }
}
package com.qf.chatroom.server;

import com.qf.chatroom.thread.ServerReadThread;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Scanner;

/**
 * 服务器端:
 *      不断读取客户端写过来的消息,给客户端不断回复数据
 *
 *      真实场景:
 *              服务器端不回复消息,作用转发消息,一般客户端和客户端聊天!
 *              张三客户端---->服务器端----->消息转发----->李四客户端
 */
public class Server {
    public static void main(String[] args) {

        //创建服务器端的Socket
        try {
            ServerSocket ss = new ServerSocket(8888) ;
            //创建List集合--默认ArrayList,存储每一个客户端!
            ArrayList<Socket> list = new ArrayList<>() ;
            System.out.println("服务器正在等待连接...");
            int i = 1 ;

            while(true){

                //监听客户端连接
                Socket socket = ss.accept() ;
                //不断的监听客户端连接
                System.out.println("第"+(i++)+"个客户端已连接...");

                //获取到的客户端通道内的字节输入和字节输出流
                InputStream in = socket.getInputStream();
                OutputStream out = socket.getOutputStream() ;
                //将每一个客户端所在Socket对象存储在List集合中
                list.add(socket) ;
                System.out.println(list) ;

                //开启服务器端读取客户端消息的子线程
                ServerReadThread srt = new ServerReadThread(socket,list) ;
                srt.start();
            }






            //创建键盘录入对象
           // Scanner sc = new Scanner(System.in) ;



            //不断去读取消息和回复消息
            /*while(true){
                //不断的回消息
                System.out.println("请回复消息: ") ;
                String fkMessage = sc.nextLine() ;

                out.write(fkMessage.getBytes());

                //服务器不关闭
            }*/

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
package com.qf.chatroom.thread;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.ArrayList;

/**
 * 服务器端读取客户端发送过来的消息的子线程
 */
public class ServerReadThread  extends  Thread{

    private Socket s  ;
    private ArrayList<Socket> list ;
    public ServerReadThread(Socket s,ArrayList<Socket> list) {
        this.s = s ;
        this.list = list ;
    }

    @Override
    public void run() {
        try {
            while(true){
                //获取到监听客户端所在的通道内的字节输入流
                InputStream in = s.getInputStream();

                //不断去读取客户端发送过来的消息
                byte[] bytes = new byte[1024] ;
                int len = in.read(bytes);
                //展示客户端发送的消息以及ip
                String ip = s.getInetAddress().getHostAddress() ;
                String receiveMessage = new String(bytes,0,len) ;
                System.out.println("消息是:"+receiveMessage) ;

                //receiveMessage "接收者:消息内容:发送者"(客户端发送端 消息格式)
                //举例:两个客户端:  0   1
                //"1:你好:0"
                //通过":"进行字符串拆分
                String[] strs = receiveMessage.split(":") ;
                //strs[0] :接收者
                String receiver = strs[0] ;
                //strs[1] :消息内容
                String messageContent = strs[1] ;
                //strs[2]:发送者
                String sender = strs[2] ;

                //获取接收者所在的通道内的Socket对象   ArrayList<Socket>通过的角标获取Socket对象
                Socket receiverSocket = list.get(Integer.parseInt(receiver)) ;
                //获取接收者所在通道内的字节输出流
                OutputStream out = receiverSocket.getOutputStream();
                //服务器端组织给客户端的消息--->写给接收者
                out.write((sender+"对你说"+messageContent).getBytes()) ;

                //服务器转发消息
                //不展示数据
                //System.out.println(ip+"---"+receiveMessage) ;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        //服务器端不关闭

    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值